diff --git a/.gitignore b/.gitignore index 5adefeceacc24d3e416a62f6676202694ff9d1eb..869ff7bc3b8757071a6b6de32660f338706e4edc 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,15 @@ Ex2/out_win_dbg Ex2/out_win_rls Ex2/out_linux_dbg Ex2/out_linux_rls + +Ex3/Ex3_task3.layout +Ex3/Ex3_task3_dbg.exe +Ex3/out_win_dbg +Ex3/out_win_rls +Ex3/out_linux_dbg +Ex3/out_linux_rls +Ex3/Ex3_task3.dot +Ex3/ex3_task3a.flt +Ex3/ex3_task3b.flt +Ex3/ex3_task3b.wav +Ex3/log_file.txt diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/dbg/libDSPE.a b/DSPE_lib_minGW/MinGW-W64_8.1.0/dbg/libDSPE.a new file mode 100644 index 0000000000000000000000000000000000000000..7d596e3f2d1e7b92b7b0df0181b964e011530e19 Binary files /dev/null and b/DSPE_lib_minGW/MinGW-W64_8.1.0/dbg/libDSPE.a differ diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/dbg/libDSPEsockets.a b/DSPE_lib_minGW/MinGW-W64_8.1.0/dbg/libDSPEsockets.a new file mode 100644 index 0000000000000000000000000000000000000000..456e3a6a0761d09446871ce8ee5b1a6486bfebe9 Binary files /dev/null and b/DSPE_lib_minGW/MinGW-W64_8.1.0/dbg/libDSPEsockets.a differ diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/DSPE_examples.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/DSPE_examples.h new file mode 100644 index 0000000000000000000000000000000000000000..5bd1f3c5e2806f862dd60ed578223c15d34de1ec --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/DSPE_examples.h @@ -0,0 +1,15 @@ +/* + * DSPE_examples.h + * + * Created on: 20.03.2017 + * Author: Marek Blok + */ + +#ifndef EXAMPLES_DSPE_EXAMPLES_H_ +#define EXAMPLES_DSPE_EXAMPLES_H_ + +int test_hello(void); +int test_sound_input(void); + + +#endif /* EXAMPLES_DSPE_EXAMPLES_H_ */ diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/DSPElib.wav b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/DSPElib.wav new file mode 100644 index 0000000000000000000000000000000000000000..061adc48e0802faf131b45941c4c13b56b41b19a Binary files /dev/null and b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/DSPElib.wav differ diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/asynchronous.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/asynchronous.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1f8f0550d1a80bb161eb859bd20ae8a398e84a8 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/asynchronous.cpp @@ -0,0 +1,83 @@ +/*! Simple asynchronous clocks usage example. + * \author Marek Blok + * \date 2010.02.26 + * \date updated 2021.04.01 + */ +#include <DSP_lib.h> + +//#define use_clock_trigger 1 + +int main(void) +{ + DSP::Clock_ptr MasterClock, SignalActivatedClock; + int temp; + long int Fp; + + DSP::log.SetLogState(DSP::e::LogState::console | DSP::e::LogState::file); + DSP::log.SetLogFileName("log_file.log"); + + DSP::log << DSP::lib_version_string() << endl << endl; + + MasterClock=DSP::Clock::CreateMasterClock(); + SignalActivatedClock=DSP::Clock::CreateMasterClock(); + + + DSP::u::WaveInput AudioIn(MasterClock, "DSPElib.wav", ".", 1); + Fp = AudioIn.GetSamplingRate(); + DSP::u::ABS ABS(false); + DSP::u::Amplifier gain(-8); + DSP::u::Addition sum; sum.SetConstInput("in2",0.9); + + DSP::u::Hold hold(SignalActivatedClock, MasterClock); + DSP::u::Amplifier gain2(8); + + DSP::u::AudioOutput AudioOut(Fp, 1); + DSP::u::FileOutput FileOut("test_out.wav", DSP::e::SampleType::ST_short, 1, DSP::e::FileType::FT_wav, Fp); + + AudioIn.Output("out") >> ABS.Input("in"); + ABS.Output("out") >> gain.Input("in"); + gain.Output("out") >> sum.Input("in1"); + + #ifdef use_clock_trigger + DSP::u::ClockTrigger CT(MasterClock, SignalActivatedClock); + DSP::u::SampleSelector sampler(MasterClock, SignalActivatedClock, false); + + sum.Output("out") >> CT.Input("act"); + sampler.Output("out") >> hold.Input("in"); + #else + DSP::u::SampleSelector sampler(MasterClock, SignalActivatedClock, true); + + sum.Output("out") >> sampler.Input("act"); + sampler.Output("out") >> hold.Input("in"); + #endif + AudioIn.Output("out") >> sampler.Input("in"); + + hold.Output("out") >> gain2.Input("in"); + + gain2.Output("out") >> AudioOut.Input("in"); + FileOut.Input("in") << gain2.Output("out"); + + DSP::Component::CheckInputsOfAllComponents(); + #ifdef use_clock_trigger + DSP::Clock::SchemeToDOTfile(MasterClock, "asynchronous_CT.dot"); + #else + DSP::Clock::SchemeToDOTfile(MasterClock, "asynchronous.dot"); + #endif + + temp=1; + do + { + DSP::Clock::Execute(MasterClock, Fp/8); + + DSP::log << "MAIN" << DSP::e::LogMode::second << temp << endl; + temp++; + } + while (AudioIn.GetBytesRead() != 0); + // process a bit more so the buffered samples are also sent to output + DSP::Clock::Execute(MasterClock, Fp/8); + + DSP::Clock::FreeClocks(); + DSP::log << "MAIN" << DSP::e::LogMode::second << "end" << endl; + + return 0; +} diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/callbacks.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/callbacks.cpp new file mode 100644 index 0000000000000000000000000000000000000000..25aa5f779986acfcf8ce83a6b3dcbd94940321da --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/callbacks.cpp @@ -0,0 +1,142 @@ +/*! Simple Digital Signal Processing Engine usage example. + * \author Marek Blok + * \date 2008.05.28 + * \date updated 2021.04.01 + */ +#include <memory> + +#include <DSP_lib.h> + +#define buffer_size 4 +DSP::Float_vector read_buffer; + +void BufferCallback(unsigned int NoOfInputs, unsigned int NoOfOutputs, DSP::Float_vector &OutputSamples, DSP::void_ptr *UserDataPtr, unsigned int UserDefinedIdentifier, DSP::Component_ptr Caller) +{ + if (NoOfInputs == DSP::Callback_Init) + { + read_buffer.resize(buffer_size); + return; + } + if (NoOfInputs == DSP::Callback_Delete) + { + read_buffer.clear(); + return; + } + + DSP::u::OutputBuffer *dsp_buffer; + int ind, counter; + + dsp_buffer = (DSP::u::OutputBuffer *)Caller->Convert2Block(); + counter = dsp_buffer->ReadBuffer(read_buffer.data(), + buffer_size*sizeof(DSP::Float), // read all samples + -2, // reset only NotificationsStep slots in buffer block + DSP::e::SampleType::ST_float); // write to read_buffer in float format + + for (ind = 0; ind < counter; ind++) + { + switch (UserDefinedIdentifier) + { + case 0: + OutputSamples[ind] = read_buffer[ind]; + break; + default: + if ((ind % 2) == 0) + OutputSamples[ind] = read_buffer[ind]; + else + OutputSamples[ind] = -read_buffer[ind]; + break; + } + } + for (ind = counter; ind < buffer_size; ind++) + OutputSamples[ind] = 0.0; +} + +int main(void) +{ + DSP::Clock_ptr MasterClock, BufferClock, MuxClock, DemuxClock; + int temp; + long int Fp; + int callback_type; + + std::shared_ptr<DSP::u::WaveInput> AudioIn; + std::shared_ptr<DSP::u::OutputBuffer> OutputBuffer; + std::shared_ptr<DSP::u::Multiplexer> Multiplexer; + std::shared_ptr<DSP::u::AudioOutput> AudioOut; + std::shared_ptr<DSP::u::Demultiplexer> Demultiplexer; + std::shared_ptr<DSP::u::Amplifier> Scale; + std::shared_ptr<DSP::u::Multiplexer> Multiplexer2; + + DSP::log.SetLogState(DSP::e::LogState::console | DSP::e::LogState::file); + DSP::log.SetLogFileName("log_file.log"); + + DSP::log << DSP::lib_version_string() << endl; + + MasterClock=DSP::Clock::CreateMasterClock(); + + + AudioIn = std::make_shared<DSP::u::WaveInput>(MasterClock, "DSPElib.wav", "."); + Fp = AudioIn->GetSamplingRate(); + + //callback_type = 0; // just copy samples + callback_type = 1; // inverse spectrum + OutputBuffer = std::make_shared<DSP::u::OutputBuffer>(buffer_size, + 1, + DSP::e::BufferType::standard, + MasterClock, + -1, + buffer_size, + BufferCallback, + callback_type); + BufferClock = OutputBuffer->GetOutputClock(); + + Multiplexer = std::make_shared<DSP::u::Multiplexer> (BufferClock, false, buffer_size); + MuxClock = Multiplexer->GetOutputClock(); + + Demultiplexer = std::make_shared<DSP::u::Demultiplexer>(false, 2); + DemuxClock = DSP::Clock::GetClock(MuxClock, 1,2); + + Scale = std::make_shared<DSP::u::Amplifier>(-1.0, 1); + Multiplexer2 = std::make_shared<DSP::u::Multiplexer>(DemuxClock, false, 2); + + AudioOut = std::make_shared<DSP::u::AudioOutput>(Fp); + + + AudioIn->Output("out") >> OutputBuffer->Input("in"); + OutputBuffer->Output("out") >> Multiplexer->Input("in"); + Multiplexer->Output("out") >> Demultiplexer->Input("in"); + + Demultiplexer->Output("out1") >> Multiplexer2->Input("in1"); + Demultiplexer->Output("out2") >> Scale->Input("in"); + Scale->Output("out") >> Multiplexer2->Input("in2"); + + Multiplexer2->Output("out") >> AudioOut->Input("in"); + + DSP::Component::CheckInputsOfAllComponents(); + DSP::Clock::SchemeToDOTfile(MasterClock, "callbacks_scheme.dot"); + + temp=1; + do + { + DSP::Clock::Execute(MasterClock, Fp/8); + + DSP::log << "MAIN" << DSP::e::LogMode::second << temp << endl; + temp++; + } + while (AudioIn->GetBytesRead() != 0); + // process a bit more so the buffered samples are also sent to output + DSP::Clock::Execute(MasterClock, Fp/8); + + AudioOut.reset(); + Multiplexer2.reset(); + Scale.reset(); + Demultiplexer.reset(); + OutputBuffer.reset(); + Multiplexer.reset(); + AudioIn.reset(); + + DSP::Clock::ListOfAllComponents(); + DSP::Clock::FreeClocks(); + DSP::log << "MAIN" << DSP::e::LogMode::second << "end" << endl; + + return 0; +} diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/echo.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/echo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05f8b17f01524ef94e3c707154aea6ab3376f4b4 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/echo.cpp @@ -0,0 +1,61 @@ +/*! Simple Digital Signal Processing Engine echo example. + * \author Marek Blok + * \date 2010.04.26 + * \date updated 2021.01.18 + */ +#include <DSP_lib.h> + +int main(void) +{ + DSP::Clock_ptr MasterClock; + int temp; + long int Fp; + + DSP::log.SetLogState(DSP::e::LogState::console | DSP::e::LogState::file); + DSP::log.SetLogFileName("log_file.log"); + + DSP::log << DSP::lib_version_string() << endl; + DSP::log << endl; + DSP::log << "Hello" << DSP::e::LogMode::second << "This is echo !!!" << endl; + + MasterClock=DSP::Clock::CreateMasterClock(); + + DSP::u::WaveInput AudioIn(MasterClock, "DSPElib.wav", "."); + Fp = AudioIn.GetSamplingRate(); + + DSP::u::Addition Add(2U); + DSP::u::LoopDelay Delay(MasterClock, Fp/2); + Delay.SetName("0.5s"); + DSP::u::Amplifier Scale(0.7); + Scale.SetName("0.7"); + + DSP::u::AudioOutput AudioOut(Fp); + + // Examples of connections + AudioIn.Output("out") >> Add.Input("in1"); + Add.Output("out") >> Delay.Input("in"); + Delay.Output("out") >> Scale.Input("in"); + Scale.Output("out") >> Add.Input("in2"); + // Note the reversed connection below !!! + AudioOut.Input("in") << Add.Output("out"); + + DSP::Component::CheckInputsOfAllComponents(); + DSP::Clock::SchemeToDOTfile(MasterClock, "echo.dot"); + + temp=0; + do + { + DSP::Clock::Execute(MasterClock, Fp/8); + + DSP::log << "MAIN" << DSP::e::LogMode::second << temp << endl; + + if (AudioIn.GetBytesRead() == 0) + temp++; + } + while (temp < 30); + + DSP::Clock::FreeClocks(); + DSP::log << "MAIN" << DSP::e::LogMode::second << "end" << endl << DSP::e::LogMode::Error << endl; + + return 0; +} diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/hello.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/hello.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e0fcc5ea9a29f7bf9c58e60b6bca35dd8cb7045 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/hello.cpp @@ -0,0 +1,52 @@ +/*! Simple Digital Signal Processing Engine usage example. + * \author Marek Blok + * \date 2006.09.11 + * \date updated 2021.01.18 + */ +#include <DSP_lib.h> + +#ifndef INCLUDE_DSPE_EXAMPLES +int main(void) +#else +#include "DSPE_examples.h" +int test_hello(void) +#endif // INCLUDE_DSPE_EXAMPLES +{ + DSP::Clock_ptr MasterClock; + string tekst; + int temp; + long int Fp; + + DSP::log.SetLogState(DSP::e::LogState::console | DSP::e::LogState::file); + DSP::log.SetLogFileName("log_file.log"); + + DSP::log << DSP::lib_version_string() << endl << endl; + DSP::log << "Hello" << DSP::e::LogMode::second << "World !!!" << endl; + + MasterClock=DSP::Clock::CreateMasterClock(); + + DSP::u::WaveInput AudioIn(MasterClock, "DSPElib.wav", "."); + Fp = AudioIn.GetSamplingRate(); + + DSP::u::AudioOutput AudioOut(Fp); + + AudioIn.Output("out") >> AudioOut.Input("in"); + + DSP::Component::CheckInputsOfAllComponents(); + DSP::Clock::SchemeToDOTfile(MasterClock, "hello.dot"); + + temp=1; + do + { + DSP::Clock::Execute(MasterClock, Fp/8); + + DSP::log << "MAIN" << DSP::e::LogMode::second << temp << endl; + temp++; + } + while (AudioIn.GetBytesRead() != 0); + + DSP::Clock::FreeClocks(); + DSP::log << DSP::e::LogMode::Error << "MAIN" << DSP::e::LogMode::second << "end" << endl; + + return 0; +} diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/macro_example.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/macro_example.cpp new file mode 100644 index 0000000000000000000000000000000000000000..26125e8186e0cb23ddd6814d09b1fdbe9c4cf98f --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/macro_example.cpp @@ -0,0 +1,103 @@ +/*! Simple macro usage example. + * \author Marek Blok + * \date 2010.02.24 + * \date updated 2021.03.31 + */ +#include <DSP_lib.h> + +class DDS_macro : public DSP::Macro +{ + private: + std::shared_ptr<DSP::u::PCCC> alpha_state_correction; + std::shared_ptr<DSP::u::Multiplication> Alpha_state_MUL; + std::shared_ptr<DSP::u::LoopDelay> Alpha_state; + + public: + DDS_macro(DSP::Clock_ptr Fp2Clock, DSP::Float exp_w_n); + + ~DDS_macro(void); +}; + +DDS_macro::DDS_macro(DSP::Clock_ptr Fp2Clock, DSP::Float w_n) : DSP::Macro("DDS", 1, 2) +{ + DSP::Complex factor = DSP::Complex(cos(w_n), sin(w_n)); + + alpha_state_correction = NULL; + Alpha_state_MUL = NULL; + Alpha_state = NULL; + + MacroInitStarted(); + + alpha_state_correction = std::make_shared<DSP::u::PCCC>(); + alpha_state_correction->SetConstInput("in.abs", 1.0); + + Alpha_state_MUL = std::make_shared<DSP::u::Multiplication>(0, 3); Alpha_state_MUL->SetConstInput("in3", factor); + this->MacroInput("in") >> alpha_state_correction->Input("in.arg"); + alpha_state_correction->Output("out") >> Alpha_state_MUL->Input("in2"); + + Alpha_state = std::make_shared<DSP::u::LoopDelay>(Fp2Clock, 1, 2); Alpha_state->SetState("in.re", 1.0); + Alpha_state->Output("out") >> Alpha_state_MUL->Input("in1"); + Alpha_state_MUL->Output("out") >> Alpha_state->Input("in"); + + Alpha_state->Output("out") >> this->MacroOutput("out"); + + MacroInitFinished(); +} + +DDS_macro::~DDS_macro(void) +{ + // this is not necessary, just remains after the previous use of delete + alpha_state_correction.reset(); + Alpha_state_MUL.reset(); + Alpha_state.reset(); +} + +int main(void) +{ + DSP::Clock_ptr MasterClock; + int temp; + long int Fp; + + DSP::log.SetLogState(DSP::e::LogState::console | DSP::e::LogState::file); + DSP::log.SetLogFileName("log_file.log"); + + DSP::log << DSP::lib_version_string() << endl << endl; + + MasterClock=DSP::Clock::CreateMasterClock(); + + + DSP::u::WaveInput AudioIn(MasterClock, "DSPElib.wav", "."); + Fp = AudioIn.GetSamplingRate(); + DDS_macro DDS(MasterClock, 0.15*DSP::M_PIx1); + DSP::u::Amplifier gain(1.0/2); + DSP::u::AudioOutput AudioOut(Fp, 2); + DSP::u::FileOutput FileOut("test_out.wav", DSP::e::SampleType::ST_short, 2, DSP::e::FileType::FT_wav, Fp); + + AudioIn.Output("out") >> gain.Input("in"); + gain.Output("out") >> DDS.Input("in"); + + DDS.Output("out") >> AudioOut.Input("in"); + DDS.Output("out") >> FileOut.Input("in"); + + DSP::Component::CheckInputsOfAllComponents(); + DSP::Clock::SchemeToDOTfile(MasterClock, "macro_wraped.dot"); + DSP::Clock::SchemeToDOTfile(MasterClock, "macro_DDS.dot", &DDS); + + DDS.SetDOTmode(DSP::e::DOTmode::DOT_macro_unwrap); + DSP::Clock::SchemeToDOTfile(MasterClock, "macro_unwraped.dot"); + + temp=1; + do + { + DSP::Clock::Execute(MasterClock, Fp/8); + + DSP::log << "MAIN" << DSP::e::LogMode::second << temp << endl; + temp++; + } + while (AudioIn.GetBytesRead() != 0); + + DSP::Clock::FreeClocks(); + DSP::log << "MAIN" << DSP::e::LogMode::second << "end" << endl; + + return 0; +} diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/makefile b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/makefile new file mode 100644 index 0000000000000000000000000000000000000000..e746da42abb6b5e7e91c88d700f4420f4e10ef24 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/makefile @@ -0,0 +1,115 @@ +# For 32-bit compilation use Mbit = 32 +CC = g++ + +ifndef TYPE + TYPE = dbg + #TYPE = rls +endif + +ifndef SRC_DIR + SRC_DIR = . +endif +ifndef SRC_DIR + DSPELIB_DIR_ROOT = ../../_DSPE_lib_minGW_/MinGW-W64_8.1.0 +endif + +ifndef Mbit + Mbit = 64 +endif +ifeq ($(TYPE),dbg) + CFLAGS = -m$(Mbit) -O0 -g3 -Wall -std=c++0x + LINKER_FLAGS = -m$(Mbit) -static-libgcc -static-libstdc++ -static +else #rls + CFLAGS = -m$(Mbit) -O3 -Wall -std=c++0x + LINKER_FLAGS = -m$(Mbit) -s -static-libgcc -static-libstdc++ -static +endif + + +SRCS = hello.cpp + +all: hello.exe echo.exe sound_input.exe multirate.exe callbacks.exe socket_server.exe socket_client.exe socket_server_2.exe socket_client_2.exe macro_example.exe asynchronous.exe asynchronous_CT.exe +#all: echo.exe + +hello.o: $(SRC_DIR)/hello.cpp + $(CC) -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/hello.cpp" -o "$(SRC_DIR)/hello.o" +hello.exe: hello.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/hello.o" -o "$(SRC_DIR)/hello.exe" $(LINKER_FLAGS) -lDSPE -lwinmm + +echo.o: $(SRC_DIR)/echo.cpp + $(CC) -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c $(SRC_DIR)/echo.cpp -o "$(SRC_DIR)/echo.o" +echo.exe: echo.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/echo.o" -o"$(SRC_DIR)/echo.exe" $(LINKER_FLAGS) -lDSPE -lwinmm + +sound_input.o: $(SRC_DIR)/sound_input.cpp + $(CC) -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c $(SRC_DIR)/sound_input.cpp -o "$(SRC_DIR)/sound_input.o" +sound_input.exe: sound_input.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/sound_input.o" -o"$(SRC_DIR)/sound_input.exe" $(LINKER_FLAGS) -lDSPE -lwinmm + +multirate.o: $(SRC_DIR)/multirate.cpp + $(CC) -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/multirate.cpp" -o "$(SRC_DIR)/multirate.o" +multirate.exe: multirate.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/multirate.o" -o"$(SRC_DIR)/multirate.exe" $(LINKER_FLAGS) -lDSPE -lwinmm + +callbacks.o: $(SRC_DIR)/callbacks.cpp + $(CC) -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" -c "$(SRC_DIR)/callbacks.cpp" -o "$(SRC_DIR)/callbacks.o" +callbacks.exe: callbacks.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/callbacks.o" -o"$(SRC_DIR)/callbacks.exe" $(LINKER_FLAGS) -lDSPE -lwinmm + +socket_server.o: $(SRC_DIR)/socket_server.cpp + $(CC) -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" -c "$(SRC_DIR)/socket_server.cpp" -o "$(SRC_DIR)/socket_server.o" +socket_server.exe: socket_server.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/socket_server.o" -o"$(SRC_DIR)/socket_server.exe" $(LINKER_FLAGS) -lDSPE -lwinmm -lDSPEsockets -lws2_32 + +socket_client.o: $(SRC_DIR)/socket_client.cpp + $(CC) -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" -c "$(SRC_DIR)/socket_client.cpp" -o "$(SRC_DIR)/socket_client.o" +socket_client.exe: socket_client.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/socket_client.o" -o"$(SRC_DIR)/socket_client.exe" $(LINKER_FLAGS) -lDSPE -lwinmm -lDSPEsockets -lws2_32 + + +socket_server_2.o: $(SRC_DIR)/socket_server_2.cpp + $(CC) -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/socket_server_2.cpp" -o "$(SRC_DIR)/socket_server_2.o" +socket_server_2.exe: socket_server_2.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/socket_server_2.o" -o"$(SRC_DIR)/socket_server_2.exe" $(LINKER_FLAGS) -lDSPE -lwinmm -lDSPEsockets -lws2_32 + +socket_client_2.o: $(SRC_DIR)/socket_client_2.cpp + $(CC) -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/socket_client_2.cpp" -o "$(SRC_DIR)/socket_client_2.o" +socket_client_2.exe: socket_client_2.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/socket_client_2.o" -o"$(SRC_DIR)/socket_client_2.exe" $(LINKER_FLAGS) -lDSPE -lwinmm -lDSPEsockets -lws2_32 + +macro_example.o: $(SRC_DIR)/macro_example.cpp + $(CC) -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/macro_example.cpp" -o "$(SRC_DIR)/macro_example.o" +macro_example.exe: macro_example.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/macro_example.o" -o"$(SRC_DIR)/macro_example.exe" $(LINKER_FLAGS) -lDSPE -lwinmm + +asynchronous.o: $(SRC_DIR)/asynchronous.cpp + $(CC) -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/asynchronous.cpp" -o "$(SRC_DIR)/asynchronous.o" +asynchronous.exe: asynchronous.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/asynchronous.o" -o"$(SRC_DIR)/asynchronous.exe" $(LINKER_FLAGS) -lDSPE -lwinmm + +asynchronous_CT.o: $(SRC_DIR)/asynchronous.cpp + $(CC) -Duse_clock_trigger -DWIN32 -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/asynchronous.cpp" -o "$(SRC_DIR)/asynchronous_CT.o" +asynchronous_CT.exe: asynchronous_CT.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/asynchronous_CT.o" -o"$(SRC_DIR)/asynchronous_CT.exe" $(LINKER_FLAGS) -lDSPE -lwinmm + +clean: + rm -f $(SRC_DIR)/hello.exe $(SRC_DIR)/hello.o + rm -f $(SRC_DIR)/echo.exe $(SRC_DIR)/echo.o + rm -f $(SRC_DIR)/sound_input.exe $(SRC_DIR)/sound_input.o + rm -f $(SRC_DIR)/asynchronous.exe $(SRC_DIR)/asynchronous.o + rm -f $(SRC_DIR)/asynchronous_CT.exe $(SRC_DIR)/asynchronous_CT.o + rm -f $(SRC_DIR)/multirate.exe $(SRC_DIR)/multirate.o + rm -f $(SRC_DIR)/callbacks.exe $(SRC_DIR)/callbacks.o + rm -f $(SRC_DIR)/socket_server.exe $(SRC_DIR)/socket_server.o + rm -f $(SRC_DIR)/socket_client.exe $(SRC_DIR)/socket_client.o + rm -f $(SRC_DIR)/socket_server_2.exe $(SRC_DIR)/socket_server_2.o + rm -f $(SRC_DIR)/socket_client_2.exe $(SRC_DIR)/socket_client_2.o + rm -f $(SRC_DIR)/macro_example.exe $(SRC_DIR)/macro_example.o + rm -f $(SRC_DIR)/*.log + rm -f $(SRC_DIR)/matlab/*.coef + rm -f $(SRC_DIR)/multirate.wav + rm -f $(SRC_DIR)/morse.wav + rm -f $(SRC_DIR)/morse_key.wav + rm -f $(SRC_DIR)/test_out.wav + rm -f $(SRC_DIR)/captured_sample.wav + rm -f $(SRC_DIR)/*.dot + rm -f $(SRC_DIR)/*.gif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/makefile-m64.linux b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/makefile-m64.linux new file mode 100644 index 0000000000000000000000000000000000000000..f2fecda3b2663a302aed8f5d0d39d6f724655304 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/makefile-m64.linux @@ -0,0 +1,131 @@ +# wersja dla kompilatora 64-bitowego (tdm-gcc 4.8.1): dodatkowa flaga -m64 +CC = g++ + +ifndef TYPE + TYPE = dbg + #TYPE = rls +endif + +ifndef SRC_DIR + SRC_DIR = . +endif +ifndef SRC_DIR + DSPELIB_DIR_ROOT = ../../_DSPE_lib_linux_/x86_64-linux-gnu-gcc_9 +endif + +ifndef Mbit + Mbit = 64 +endif +ifeq ($(TYPE),dbg) + CFLAGS = -m$(Mbit) -O0 -g3 -Wall -std=c++0x + LINKER_FLAGS = -m$(Mbit) -static-libgcc -static-libstdc++ +else #rls + CFLAGS = -m$(Mbit) -O3 -Wall -std=c++0x + LINKER_FLAGS = -m$(Mbit) -s -static-libgcc -static-libstdc++ +endif +# -static causes problems with asound lib linking + +DFLAGS = -DLINUX -DDEVCPP +LIBS = -lDSPE -lasound # asound library must come after the DSPElib +LIBS_SOCKETS = -lDSPEsockets # -lws2_32 + +SRCS = hello.cpp + +#all: hello.exe echo.exe multirate.exe callbacks.exe socket_server.exe socket_client.exe #socket_server_2.exe socket_client_2.exe macro_example.exe asynchronous.exe asynchronous_CT.exe +all: DSP_hello DSP_echo DSP_sount_input DSP_multirate DSP_callbacks DSP_socket_server DSP_socket_client DSP_socket_server_2 DSP_socket_client_2 DSP_macro_example DSP_asynchronous DSP_asynchronous_CT + +hello.o: $(SRC_DIR)/hello.cpp + $(CC) $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/hello.cpp" -o "$(SRC_DIR)/hello.o" + +DSP_hello: hello.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/hello.o" -o "$(SRC_DIR)/DSP_hello" $(LINKER_FLAGS) $(LIBS) + +echo.o: $(SRC_DIR)/echo.cpp + $(CC) $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/echo.cpp" -o "$(SRC_DIR)/echo.o" + +DSP_echo: echo.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/echo.o" -o "$(SRC_DIR)/DSP_echo" $(LINKER_FLAGS) $(LIBS) + +sount_input.o: $(SRC_DIR)/sount_input.cpp + $(CC) $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/sount_input.cpp" -o "$(SRC_DIR)/sount_input.o" + +DSP_sount_input: sount_input.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/sount_input.o" -o "$(SRC_DIR)/DSP_sount_input" $(LINKER_FLAGS) $(LIBS) + +multirate.o: $(SRC_DIR)/multirate.cpp + $(CC) $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/multirate.cpp" -o "$(SRC_DIR)/multirate.o" + +DSP_multirate: multirate.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/multirate.o" -o "$(SRC_DIR)/DSP_multirate" $(LINKER_FLAGS) $(LIBS) + +callbacks.o: $(SRC_DIR)/callbacks.cpp + $(CC) $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/callbacks.cpp" -o "$(SRC_DIR)/callbacks.o" + +DSP_callbacks: callbacks.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/callbacks.o" -o "$(SRC_DIR)/DSP_callbacks" $(LINKER_FLAGS) $(LIBS) + +socket_server.o: $(SRC_DIR)/socket_server.cpp + $(CC) $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/socket_server.cpp" -o "$(SRC_DIR)/socket_server.o" + +DSP_socket_server: socket_server.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/socket_server.o" -o "$(SRC_DIR)/DSP_socket_server" $(LINKER_FLAGS) $(LIBS) $(LIBS_SOCKETS) + +socket_client.o: $(SRC_DIR)/socket_client.cpp + $(CC) $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/socket_client.cpp" -o "$(SRC_DIR)/socket_client.o" + +DSP_socket_client: socket_client.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/socket_client.o" -o "$(SRC_DIR)/DSP_socket_client" $(LINKER_FLAGS) $(LIBS) $(LIBS_SOCKETS) + +socket_server_2.o: $(SRC_DIR)/socket_server_2.cpp + $(CC) $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/socket_server_2.cpp" -o "$(SRC_DIR)/socket_server_2.o" + +DSP_socket_server_2: socket_server_2.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/socket_server_2.o" -o "$(SRC_DIR)/DSP_socket_server_2" $(LINKER_FLAGS) $(LIBS) $(LIBS_SOCKETS) + +socket_client_2.o: $(SRC_DIR)/socket_client_2.cpp + $(CC) $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/socket_client_2.cpp" -o "$(SRC_DIR)/socket_client_2.o" + +DSP_socket_client_2: socket_client_2.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/socket_client_2.o" -o "$(SRC_DIR)/DSP_socket_client_2" $(LINKER_FLAGS) $(LIBS) $(LIBS_SOCKETS) + +macro_example.o: $(SRC_DIR)/macro_example.cpp + $(CC) $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/macro_example.cpp" -o "$(SRC_DIR)/macro_example.o" + +DSP_macro_example: macro_example.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/macro_example.o" -o "$(SRC_DIR)/DSP_macro_example" $(LINKER_FLAGS) $(LIBS) + +asynchronous.o: $(SRC_DIR)/asynchronous.cpp + $(CC) $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/asynchronous.cpp" -o "$(SRC_DIR)/asynchronous.o" + +DSP_asynchronous: asynchronous.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/asynchronous.o" -o "$(SRC_DIR)/DSP_asynchronous" $(LINKER_FLAGS) $(LIBS) + +asynchronous_CT.o: $(SRC_DIR)/asynchronous.cpp + $(CC) -Duse_clock_trigger $(DFLAGS) -I"$(DSPELIB_DIR_ROOT)/include" -I"$(DSPELIB_DIR_ROOT)/include/$(TYPE)" $(CFLAGS) -c "$(SRC_DIR)/asynchronous.cpp" -o "$(SRC_DIR)/asynchronous_CT.o" + +DSP_asynchronous_CT: asynchronous_CT.o + $(CC) -L"$(DSPELIB_DIR_ROOT)/$(TYPE)" "$(SRC_DIR)/asynchronous_CT.o" -o "$(SRC_DIR)/DSP_asynchronous_CT" $(LINKER_FLAGS) $(LIBS) + + +clean: + rm -f $(SRC_DIR)/DSP_hello $(SRC_DIR)/hello.o + rm -f $(SRC_DIR)/DSP_echo $(SRC_DIR)/echo.o + rm -f $(SRC_DIR)/DSP_sound_input $(SRC_DIR)/sound_input.o + rm -f $(SRC_DIR)/DSP_asynchronous $(SRC_DIR)/asynchronous.o + rm -f $(SRC_DIR)/DSP_asynchronous_CT $(SRC_DIR)/asynchronous_CT.o + rm -f $(SRC_DIR)/DSP_multirate $(SRC_DIR)/multirate.o + rm -f $(SRC_DIR)/DSP_callbacks $(SRC_DIR)/callbacks.o + rm -f $(SRC_DIR)/DSP_socket_server $(SRC_DIR)/socket_server.o + rm -f $(SRC_DIR)/DSP_socket_client $(SRC_DIR)/socket_client.o + rm -f $(SRC_DIR)/DSP_socket_server_2 $(SRC_DIR)/socket_server_2.o + rm -f $(SRC_DIR)/DSP_socket_client_2 $(SRC_DIR)/socket_client_2.o + rm -f $(SRC_DIR)/DSP_macro_example $(SRC_DIR)/macro_example.o + rm -f $(SRC_DIR)/*.log + rm -f $(SRC_DIR)/matlab/*.coef + rm -f $(SRC_DIR)/multirate.wav + rm -f $(SRC_DIR)/morse.wav + rm -f $(SRC_DIR)/morse_key.wav + rm -f $(SRC_DIR)/test_out.wav + rm -f $(SRC_DIR)/captured_sample.wav + rm -f $(SRC_DIR)/*.dot + rm -f $(SRC_DIR)/*.gif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/matlab/multirate_filters.m b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/matlab/multirate_filters.m new file mode 100644 index 0000000000000000000000000000000000000000..30f7863c6581d0c3d4748f63106bb2bcda84de44 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/matlab/multirate_filters.m @@ -0,0 +1,25 @@ +function h=multirate_filters + +%decimation filter 22050 -> 8000 +Fp1 = 22050; Fp2 = 8000; +M = 441; L = 160; +N=160*21; +n = -N/2:(N/2-1); + +wind = hann(N).'; +wind = wind / sum(wind); +h = sinc(pi*3000/(L*Fp1)*n); +h = 4.48*h.*wind; + +figure(1) +plot(h) +pause + +figure(2) +freqz(h,1, 8*2048, L*Fp1) + + +dane.h = L*h; +dane.Fp = Fp1; +save_filter_coef('LPF_22050_8000', dane); + diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/matlab/save_filter_coef.m b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/matlab/save_filter_coef.m new file mode 100644 index 0000000000000000000000000000000000000000..5a1bf6b5e73b6351236dce20deef83096b96eb4c --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/matlab/save_filter_coef.m @@ -0,0 +1,226 @@ +function save_filter_coef(filename, coefficients, file_version) +% save_filter_coef(filename, coefficients [, file_version]) +% +% FIR filter coefficients +% coefficients.h +% - can be cell vector to store multiple FIR impulse responces +% - if any of the impulse responses is complex then all responses will +% be stored as complex +% IIR filter coefficients +% coefficients.a +% coefficients.b +% +% For file_version >= 1 (default == 0), +% coefficients.Fp - sampling frequency +% +% This file is a part of Digital Signal Processing Engine +% +% File format (*.coef) - this is open format, for general use +% * (not only for storing coefficients) +% +% File format (*.h) - this is C++ header file for DSPElib with hardcoded *.coef equivalent +% +% \author Marek Blok +% \date 2020.02.22 + +if nargin == 2, + file_version = 0; +end + +ind = find(filename == '.'); +if length(ind) == 0, + filename = [filename, '.coef']; +end + +% detect mode based on file extention +[PATHSTR,NAME,EXT] = fileparts(filename); +switch EXT + case '.h' + mode = 'h-file'; + plik = fopen(filename, 'wt'); + + case '.coef' + mode = 'coefs-file'; + plik = fopen(filename, 'wb'); + + otherwise + mode = 'unknown-file'; + error(mode); +end + +switch mode + case 'h-file' + fprintf(plik, '// save_filter_coef output (hard coded coefficients)\n'); + fprintf(plik, '#pragma once\n'); + fprintf(plik, '#include <DSP_lib.h>\n'); + fprintf(plik, '\n'); + + if isfield(coefficients, 'h'), + h = coefficients.h; + + for ind_h = 0:length(h)-1 + fprintf(plik, 'DSP::Float_vector Farrow_coefs_row_%i = {', ind_h); + h_tmp = h{ind_h+1}; + for ind_p = 0:length(h_tmp)-1, + if ind_p > 0 + fprintf(plik, ', '); + end + fprintf(plik, '%.15ff', h_tmp(ind_p+1)); + end + %0.1f, 0.2f, 0.1f + fprintf(plik, '};\n'); + end + fprintf(plik, '\n'); + + %vector <DSP::Float_vector> Farrow_coefs = { coefs_0, coefs_1, coefs_2 }; + fprintf(plik, 'vector <DSP::Float_vector> Farrow_coefs = {'); + for ind_h = 0:length(h)-1 + if ind_h > 0 + fprintf(plik, ', '); + end + if (ind_h < length(h_tmp)) & (rem(ind_h, 5) == 0) + fprintf(plik, '\n '); + end + fprintf(plik, 'Farrow_coefs_row_%i', ind_h); + end + fprintf(plik, '\n };\n'); + + fprintf(plik, '\n'); + fprintf(plik, 'const unsigned int p_Farrow = %i; // should be equal to Farrow_coefs[0].size()-1\n', length(h{1})-1); + fprintf(plik, 'const unsigned int N_FSD = %i; // should be equal to Farrow_coefs.size()\n', length(h)); + end + + if isfield(coefficients, 'b'), + fclose all; + error('unsupported: coefficients.b'); + end + if isfield(coefficients, 'a'), + fclose all; + error('unsupported: coefficients.a'); + end + + case 'coefs-file' + % * - (uchar) 1B - file version number + fwrite(plik, file_version, 'uchar'); + + switch file_version, + case 0, + case 1, + % * - (uint) 4B - Sampling frequency + if isfield(coefficients, 'Fp'), + fwrite(plik, coefficients.Fp, 'uint32'); + else + fclose(plik); + error('Input data does not contain Fp'); + end + otherwise, + fclose(plik); + error('This version of coefficients file is unsupported'); + end + + if isfield(coefficients, 'h'), + isFIR = 1; + if iscell(coefficients.h) + resp_no = length(coefficients.h); + % if resp_no = 1; + % coefficients.h = coefficients.h{1}; + % end + else + resp_no = 1; + end + if resp_no == 1, + isComplex = any(imag(coefficients.h(:))); + else + isComplex = false; + for ind_resp = 1:resp_no, + isComplex = isComplex | any(imag(coefficients.h{ind_resp}(:))); + end + end + else + isFIR = 0; + isComplex = any(imag(coefficients.a(:))) | any(imag(coefficients.b(:))); + end + + % * - data - coefficients data (depends on fle version) + % * . + % * Data segment format: + % * -# (version: 0x00) + % * - (uchar) 1B - number of sample dimensions + % * 1 - real, 2 - complex, ... + if isComplex, + fwrite(plik, 2, 'uchar'); % complex + else + fwrite(plik, 1, 'uchar'); % real + end + % * - (uchar) 1B - sample component type + % * - DSP::e::FileType::FT_float (=1) : C++ float (32bit floating point) + % * - DSP::e::FileType::FT_short (=2) : C++ short (16bit signed integer) + % * - DSP::e::FileType::FT_uchar (=3) : C++ unsigned char (8bit unsigned integer with bias (0x80)) + % * - DSP::e::FileType::FT_double (=7) : C++ double (64bit floating point) + % * - DSP::e::FileType::FT_long_double (=8) : C++ long double (80bit floating point) + fwrite(plik, 1, 'uchar'); + + % * - (uchar) 1B - number of vectors + % * - 1 - FIR filter coefficients (one vector) + % * - 2 - IIR filter coefficients (two vectors) + % * - (x number of vectors) + % * - (ushort) 2B - number of samples in vector + % * - (x number of samples) + % * - (x number of sample dimensions) + % * - (sample componet type) xB - sample component + % * e.g. real, imag part + if isFIR, + fwrite(plik, resp_no, 'uchar'); + + if iscell(coefficients.h) + for ind_resp = 1:resp_no, + N_FIR = length(coefficients.h{ind_resp}); + fwrite(plik, N_FIR, 'uint16'); + if isComplex, + dane(1:2:2*N_FIR) = real(coefficients.h{ind_resp}); + dane(2:2:2*N_FIR) = imag(coefficients.h{ind_resp}); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.h{ind_resp}), 'float'); + end + end + else + N_FIR = length(coefficients.h); + fwrite(plik, N_FIR, 'uint16'); + if isComplex, + dane(1:2:2*N_FIR) = real(coefficients.h); + dane(2:2:2*N_FIR) = imag(coefficients.h); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.h), 'float'); + end + end + + else + fwrite(plik, 2, 'uchar'); + + N_a = length(coefficients.a); + fwrite(plik, N_a, 'uint16'); + if isComplex, + dane(1:2:2*N_a) = real(coefficients.a); + dane(2:2:2*N_a) = imag(coefficients.a); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.a), 'float'); + end + + + N_b = length(coefficients.b); + fwrite(plik, N_b, 'uint16'); + if isComplex, + dane(1:2:2*N_b) = real(coefficients.b); + dane(2:2:2*N_b) = imag(coefficients.b); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.b), 'float'); + end + end + +end +fclose(plik); + diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/matlab/socket_filters.m b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/matlab/socket_filters.m new file mode 100644 index 0000000000000000000000000000000000000000..34c89c00b211aee06edf93ca7591bc45feaf91b0 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/matlab/socket_filters.m @@ -0,0 +1,50 @@ +function h=socket_filters + +%interpolation filter 8000 -> 48000 +Fp1 = 8000; Fp2 = 48000; +M = 1; L = 6; +N=L*21; +n = -N/2:(N/2-1); + +wind = hann(N).'; +wind = wind / sum(wind); +h = sinc(pi*3000/(L*Fp1)*n); +h = 4.48*h.*wind; + +figure(1) +plot(h) +pause + +figure(2) +freqz(h,1, 8*2048, L*Fp1) + + +dane.h = L*h; +dane.Fp = Fp1; +save_filter_coef('LPF_8000_48000', dane); + + + +%interpolation filter 8000 -> 11025 +Fp1 = 8000; Fp2 = 11025; +M = 320; L = 441; +N=L*21; +n = -N/2:(N/2-1); + +wind = hann(N).'; +wind = wind / sum(wind); +h = sinc(pi*3000/(L*Fp1)*n); +h = 4.48*h.*wind; + +figure(1) +plot(h) +pause + +figure(2) +freqz(h,1, 8*2048, L*Fp1) + + +dane.h = L*h; +dane.Fp = Fp1; +save_filter_coef('LPF_8000_11025', dane); + diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/multirate.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/multirate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91638e373368de48ec2dc96b3c67e35b5b860cff --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/multirate.cpp @@ -0,0 +1,221 @@ +/*! Digital Signal Processing Engine example. + * Multirate algorithm. + * + * Execution: + * multirate [input_mode] + * where input_mode = 0, 1 or 2 + * + * \author Marek Blok + * \date 2006.09.23 + * \date updated 2021.03.31 + */ +#include <memory> + +#include <DSP_lib.h> + +int main(int argn, char *args[]) +{ + int input_mode = 0; + int Fp1 = 22050; + int Fp2 = 8000; + DSP::LoadCoef coef_info; + int L, M; + int N_LPF_resample; +// DSP::Float_ptr h_LPF_resample; + DSP::Float_vector h_LPF_resample; + float sound_factor = 0.5; // input sound gain - to avoid saturation in processed sound + float factor = 0.6; // loop decay factor + float delay = 0.7; // loop delay in seconds + + if (argn == 2) + { + input_mode = args[1][0]-'0'; + } + + /*************************************************************/ + std::map<std::string,std::shared_ptr<DSP::Component> > blocks; + // DSP::Component *SoundIn = NULL; + // DSP::u::Amplifier *SoundInFactor = NULL; + // DSP::u::Const *Chirp_frequ = NULL; + // DSP::u::Accumulator *Chirp_Acum = NULL; + // DSP::u::Addition *Adder = NULL; + // DSP::u::SamplingRateConversion *Resampler_InOut = NULL; + // DSP::u::SamplingRateConversion *Resampler_OutIn = NULL; + // DSP::u::Amplifier *Factor = NULL; + // DSP::u::LoopDelay *Delay = NULL; + // DSP::u::AudioOutput *SoundOut = NULL; + // DSP::u::FileOutput *FileOut = NULL; + + /*************************************************************/ + // Log file setup + DSP::log.SetLogFileName("log_file.log"); + DSP::log.SetLogState(DSP::e::LogState::file | DSP::e::LogState::console); + + DSP::log << DSP::lib_version_string() << endl << endl; + /*************************************************************/ + DSP::Clock_ptr MasterClock, OutputClock; + MasterClock=DSP::Clock::CreateMasterClock(); + + /*************************************************************/ + //Input source creation + switch (input_mode) + { + case 2: // Chirp signal + blocks["SoundIn"] = std::make_shared<DSP::u::DDScos>(MasterClock); + + blocks["SoundIn"]->Convert2Block()->SetConstInput("ampl",1.0); //Amplitude + blocks["SoundIn"]->Convert2Block()->SetConstInput("phase",0.0); //Initial phase + + blocks["Chirp_frequ"] = std::make_shared<DSP::u::Const>(MasterClock, DSP::M_PIx2*0.5/Fp1/2); + blocks["Chirp_Acum"] = std::make_shared<DSP::u::Accumulator>(); + + blocks["Chirp_frequ"]->Output("out") >> blocks["Chirp_Acum"]->Input("in"); + blocks["Chirp_Acum"]->Output("out") >> blocks["SoundIn"]->Convert2Block()->Input("puls"); + break; + + case 1: //Input from soundcard + blocks["SoundIn"] = std::make_shared<DSP::u::AudioInput>(MasterClock, Fp1, 1, 16); + break; + + case 0: //Input from file + default: + input_mode = 0; + + blocks["SoundIn"] = std::make_shared<DSP::u::WaveInput>(MasterClock, "DSPElib.wav", ".", 1); + Fp1 = ((DSP::u::WaveInput *)blocks["SoundIn"]->Convert2Source())->GetSamplingRate(); + + if (Fp1 != 22050) + { + DSP::log << DSP::e::LogMode::Error << "Input wave file's sampling rate must be 22050 Sa/s" << endl; + + blocks["SoundIn"].reset(); + return 1; + } + break; + } + + blocks["SoundInFactor"] = std::make_shared<DSP::u::Amplifier>(sound_factor); + + /* ***************************************** */ + // Conversion from 22050 Sa/s to 8000 Sa/s + L = 160; M = 441; + coef_info.Open("LPF_22050_8000.coef", "matlab"); + N_LPF_resample = coef_info.GetSize(0); + + if (N_LPF_resample < 1) + { + // problem + N_LPF_resample = L*21; + h_LPF_resample.resize(N_LPF_resample, 0.0); + + // design LPF filter with gain equal L + DSP::f::Hann(N_LPF_resample, h_LPF_resample.data(), true); + for (int n = 0; n < N_LPF_resample; n++) + { + h_LPF_resample[n] *= DSP::f::sinc((DSP::M_PIx1*3000)/(L*Fp1)*(n-N_LPF_resample/2)); + h_LPF_resample[n] *= 4.48; + h_LPF_resample[n] *= L; + } + + DSP::log << "Filter coeficients files should be generated beforehand using >>multirate_filters.m<<" << endl; + } + else + { + coef_info.Load(h_LPF_resample); + } + + blocks["Resampler_InOut"] = std::make_shared<DSP::u::SamplingRateConversion>(false, MasterClock, L, M, h_LPF_resample); + OutputClock = blocks["Resampler_InOut"]->GetOutputClock(); + + /* ***************************************** */ + // Conversion from 8000 Sa/s to 22050 Sa/s + // \note filter can be reused + L = 441; M = 160; + for (int n = 0; n < N_LPF_resample; n++) + { + h_LPF_resample[n] /= M; + h_LPF_resample[n] *= L; + } + blocks["Resampler_OutIn"] = std::make_shared<DSP::u::SamplingRateConversion>(false, OutputClock, L, M, h_LPF_resample); + + /*************************************************************/ + // Output to the soundcard + blocks["SoundOut"] = std::make_shared<DSP::u::AudioOutput>(Fp2, 1, 16); + // Output to the mono 16bit *.wav file + blocks["FileOut"] = std::make_shared<DSP::u::FileOutput>("multirate.wav", DSP::e::SampleType::ST_short, 1, DSP::e::FileType::FT_wav, Fp2); + + /*************************************************************/ + blocks["Adder"] = std::make_shared<DSP::u::Addition>(2); + blocks["Factor"] = std::make_shared<DSP::u::Amplifier>(factor); + blocks["Delay"] = std::make_shared<DSP::u::LoopDelay>(OutputClock, (int)(delay * Fp2)); + + /*************************************************************/ + // Connections definitions + blocks["SoundIn"]->Output("out") >> blocks["SoundInFactor"]->Input("in"); + blocks["SoundInFactor"]->Output("out") >> blocks["Adder"]->Input("real_in1"); + blocks["Adder"]->Output("out") >> blocks["Resampler_InOut"]->Input("in"); + blocks["Resampler_InOut"]->Output("out") >> blocks["SoundOut"]->Input("in"); + blocks["Resampler_InOut"]->Output("out") >> blocks["FileOut"]->Input("in"); + blocks["Resampler_InOut"]->Output("out") >> blocks["Factor"]->Input("in"); + blocks["Factor"]->Output("out") >> blocks["Delay"]->Input("in"); + blocks["Delay"]->Output("out") >> blocks["Resampler_OutIn"]->Input("in"); + blocks["Resampler_OutIn"]->Output("out") >> blocks["Adder"]->Input("real_in2"); + + + ///////////////////////////////// + // check if there are signals + // connected to all inputs + DSP::Component::CheckInputsOfAllComponents(); + DSP::Clock::SchemeToDOTfile(MasterClock, "multirate.dot"); + + // *********************************** // + // *********************************** // + int SamplesInSegment = 512; + int64_t NoOfSamplesProcessed = 0; + // 10 seconds + #define MAX_SAMPLES_TO_PROCESS 10*8000 + while(NoOfSamplesProcessed < MAX_SAMPLES_TO_PROCESS) + { + + // ********************************************************** // + DSP::Clock::Execute(OutputClock, SamplesInSegment); + // ********************************************************** // + + if (input_mode == 0) + { + if (((DSP::u::WaveInput *)blocks["SoundIn"]->Convert2Source())->GetBytesRead() > 0) + { + NoOfSamplesProcessed = 0; // Play the whole file + } + else // Play five seconds more + if (NoOfSamplesProcessed < MAX_SAMPLES_TO_PROCESS - 5*8000) + NoOfSamplesProcessed = MAX_SAMPLES_TO_PROCESS - 5*8000; + } + + NoOfSamplesProcessed += SamplesInSegment; + // ********************************************************** // + } + + + + /*************************************************************/ + blocks["SoundIn"].reset(); + blocks["SoundInFactor"].reset(); + blocks["Chirp_Acum"].reset(); + blocks["Chirp_frequ"].reset(); + blocks["Adder"].reset(); + blocks["Resampler_InOut"].reset(); + blocks["Resampler_OutIn"].reset(); + blocks["Factor"].reset(); + blocks["Delay"].reset(); + blocks["SoundOut"].reset(); + blocks["FileOut"].reset(); + + /*************************************************************/ + DSP::Clock::ListOfAllComponents(); + + /*************************************************************/ + DSP::Clock::FreeClocks(); + + return 0; +} diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/processing_block_example.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/processing_block_example.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb4e4b15f169925218c4aecbcbaa6a3df0613c5e --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/processing_block_example.cpp @@ -0,0 +1,85 @@ +/**************************************************/ +//! CCPC - cartesian coordinated to polar coordinates converter +/*! + * + * \f$ p[n]=|u[n]| + j \cdot \arg(u[n]) \f$ + * + * Inputs and Outputs names: + * - Output: + * -# "out" (complex valued) + * -# "out.abs" - absolute value (real component)\n + * "out.arg" - phase (imag component) + * -# "out.re" == "out.abs"\n + * "out.im" == "out.arg + * - Input: + * -# "in" - complex input + * -# "in.re" - real component\n + * "in.im" - imag component + */ +class DSP::u::CCPC : public DSP::Block +{ + private: + DSP::Complex in_value; + + static void InputExecute(DSP::Block *block, int InputNo, DSP::Float value, DSP::Component *Caller); + public: + CCPC(void); + ~CCPC(void); +}; + + + +#define THIS ((DSP::u::CCPC *)block) +/**************************************************/ +// CCPC - cartesian coordinated to polar coordinates converter +DSP::u::CCPC::CCPC() + : DSP::Block() +{ + SetName("CCPC", false); + + SetNoOfInputs(2, false); + DefineInput("in", 0, 1); + DefineInput("in.re", 0); + DefineInput("in.im", 1); + SetNoOfOutputs(2); + DefineOutput("out", 0, 1); + DefineOutput("out.abs", 0); + DefineOutput("out.arg", 1); + DefineOutput("out.re", 0); + DefineOutput("out.im", 1); + + ClockGroups.AddInputs2Group("all", 0, NoOfInputs-1); + ClockGroups.AddOutputs2Group("all", 0, NoOfOutputs-1); + + Execute_ptr = &InputExecute; +} + +DSP::u::CCPC::~CCPC() +{ +} + +void DSP::u::CCPC::InputExecute(DSP::Block *block, int InputNo, DSP::Float value, DSP::Component *Caller) +{ + if (InputNo==0) + THIS->in_value.re = value; + else + THIS->in_value.im = value; + THIS->NoOfInputsProcessed++; + + if (THIS->NoOfInputsProcessed < THIS->NoOfInputs) + return; + THIS->NoOfInputsProcessed = 0; + + +// OutputBlocks[0]->Execute(OutputBlocks_InputNo[0], in_value.abs(), this); + THIS->OutputBlocks[0]->Execute_ptr( + THIS->OutputBlocks[0], + THIS->OutputBlocks_InputNo[0], + THIS->in_value.abs(), block); +// OutputBlocks[1]->Execute(OutputBlocks_InputNo[1], in_value.angle(), this); + THIS->OutputBlocks[1]->Execute_ptr( + THIS->OutputBlocks[1], + THIS->OutputBlocks_InputNo[1], + THIS->in_value.angle(), block); +}; +#undef THIS diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/rundot.bat b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/rundot.bat new file mode 100644 index 0000000000000000000000000000000000000000..de6d50737f7c5682f2149cf63b1fdc85708c434b --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/rundot.bat @@ -0,0 +1,13 @@ +path = "c:\Program Files (x86)\Graphviz2.38\bin\";%path% + +dot -Tgif macro_DDS.dot -omacro_DDS.gif +dot -Tgif macro_unwraped.dot -omacro_unwraped.gif +dot -Tgif macro_wraped.dot -omacro_wraped.gif +dot -Tgif asynchronous.dot -oasynchronous.gif +dot -Tgif socket_server_2.dot -osocket_server_2.gif +dot -Tgif socket_client_2.dot -osocket_client_2.gif +dot -Tgif callbacks_scheme.dot -ocallbacks_scheme.gif +dot -Tgif hello.dot -ohello.gif +dot -Tgif echo.dot -oecho.gif +dot -Tgif sound_input.dot -osound_input.gif +dot -Tgif multirate.dot -omultirate.gif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_client.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..15a8e696c52e21cec101c6d6edfdd8738cf7ae69 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_client.cpp @@ -0,0 +1,53 @@ +/*! Digital Signal Processing Engine sockets usage example. + * Simple client application. + * \author Marek Blok + * \date 2008.10.06 + * \date updated 2021.01.18 + */ +#include <DSP_sockets.h> +#include <DSP_lib.h> + +int main(void) +{ + DSP::Clock_ptr MasterClock; + int temp; + long int Fp; + + DSP::log.SetLogState(DSP::e::LogState::console | DSP::e::LogState::file); + DSP::log.SetLogFileName("log_file_client.log"); + + DSP::log << DSP::lib_version_string() << endl << endl; + + MasterClock=DSP::Clock::CreateMasterClock(); + + DSP::u::WaveInput AudioIn(MasterClock, "DSPElib.wav", "."); + //Fp = AudioIn.GetSamplingRate(); + + // use client socket + //DSP::u::SocketInput in_socket(MasterClock, "153.19.48.213", true); + DSP::u::SocketInput in_socket(MasterClock, "127.0.0.1", true, 0x00000002); + Fp = 22050; + + DSP::u::SocketOutput out_socket("127.0.0.1", true, 0x00000001); + DSP::u::AudioOutput AudioOut(Fp); + + in_socket.Output("out") >> AudioOut.Input("in"); + AudioIn.Output("out") >> out_socket.Input("in"); + + DSP::Component::CheckInputsOfAllComponents(); + + temp=1; + do + { + DSP::Clock::Execute(MasterClock, Fp/8); + + DSP::log << "MAIN" << DSP::e::LogMode::second << temp << endl; + temp++; + } + while (in_socket.GetBytesRead() != 0); + + DSP::Clock::FreeClocks(); + DSP::log << DSP::e::LogMode::Error << "MAIN" << DSP::e::LogMode::second << "end" << endl; + + return 0; +} diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_client_2.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_client_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf1095e7a526767119481ef0702efec96943b5db --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_client_2.cpp @@ -0,0 +1,70 @@ +/*! Digital Signal Processing Engine sockets usage example. + * Simple client application (2). + * \author Marek Blok + * \date 2010.02.09 + * \date updated 2021.01.18 + */ +#include <DSP_sockets.h> +#include <DSP_lib.h> + +int main(void) +{ + DSP::Clock_ptr MasterClock; + int temp; + unsigned long Fp1, Fp2, M, L; + DSP::LoadCoef coef_info; + int N_SRC; DSP::Float_vector h_SRC; + + DSP::log.SetLogState(DSP::e::LogState::console | DSP::e::LogState::file); + DSP::log.SetLogFileName("log_file_client.log"); + + DSP::log << DSP::lib_version_string() << endl << endl; + + coef_info.Open("LPF_8000_11025.coef", "matlab"); + N_SRC = coef_info.GetSize(0); + if (N_SRC < 1) + { + DSP::log << "Filter coefficients files should be generated using >>socket_filters.m<<" << endl; + return 1; + } + else + { + coef_info.Load(h_SRC); + } + + MasterClock=DSP::Clock::CreateMasterClock(); + + // use client socket +// DSP::u::SocketInput in_socket(MasterClock, "127.0.0.1", true, 0x00000003); + string server_address = "127.0.0.1:10000"; + DSP::u::SocketInput in_socket(MasterClock, server_address, true, 0x00000003); + in_socket.SetName(server_address); + Fp1 = 8000; Fp2 = 11025; + M = 320; L = 441; + DSP::u::SamplingRateConversion SRC(false,MasterClock, L, M, h_SRC); + DSP::u::AudioOutput AudioOut(Fp2); + + in_socket.Output("out") >> SRC.Input("in"); + SRC.Output("out") >> AudioOut.Input("in"); + + DSP::u::FileOutput WAVEfile("morse.wav", DSP::e::SampleType::ST_short, 1, DSP::e::FileType::FT_wav, Fp2); + SRC.Output("out") >> WAVEfile.Input("in"); + + DSP::Component::CheckInputsOfAllComponents(); + DSP::Clock::SchemeToDOTfile(MasterClock, "socket_client_2.dot"); + + // in_socket.WaitForConnection(); <== client not server + temp=1; + do + { + DSP::Clock::Execute(MasterClock, Fp1/4); + + DSP::log << "MAIN" << DSP::e::LogMode::second << temp + << " (" << in_socket.GetBytesRead() << ")" << endl; + temp++; + } + while (in_socket.GetBytesRead() != 0); + + DSP::Clock::FreeClocks(); + return 0; +} diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_server.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6e6a067eb07243b73b28f3e9f2f397d778a2669b --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_server.cpp @@ -0,0 +1,66 @@ +/*! Digital Signal Processing Engine sockets usage example. + * Simple server application. + * \author Marek Blok + * \date 2008.10.06 + * \date updated 2021.01.18 + */ +#include <DSP_sockets.h> +#include <DSP_lib.h> +#include <DSP_modules_misc.h> + +int main(void) +{ + DSP::Clock_ptr MasterClock; + int temp; + long int Fp; + + DSP::log.SetLogState(DSP::e::LogState::console | DSP::e::LogState::file); + DSP::log.SetLogFileName("log_file.log"); + + DSP::log << DSP::lib_version_string() << endl << endl; + + MasterClock=DSP::Clock::CreateMasterClock(); + +// DSP::u::WaveInput AudioIn(MasterClock, "DSPElib.wav", "."); +// Fp = AudioIn.GetSamplingRate(); + Fp = 22050; + DSP::u::DDScos AudioIn(MasterClock, false, 1.0, DSP::Float(1000*DSP::M_PIx2/Fp)); + DSP::u::MORSEkey MorseKey(MasterClock, 20, Fp); + MorseKey.AddString("Digital Signal Processing Engine library"); + DSP::u::RealMultiplication Mul(2); + + AudioIn.Output("out") >> Mul.Input("in1"); + MorseKey.Output("out") >> Mul.Input("in2"); + + DSP::u::SocketInput in_socket(MasterClock, "0.0.0.0", false, 0x00000001); + DSP::u::AudioOutput AudioOut(Fp); + in_socket.Output("out") >> AudioOut.Input("in"); + + // use server socket + DSP::u::SocketOutput out_socket("0.0.0.0", false, 0x00000002); + Mul.Output("out") >> out_socket.Input("in"); +// DSP::u::FileOutput FileOut("server.flt", DSP::e::SampleType::ST_float, 1, DSP::e::FileType::FT_flt, Fp); +// AudioIn.Output("out") >> FileOut.Input("in"); + + DSP::Component::CheckInputsOfAllComponents(); + + + //! \bug Implement WaitForAllConnections(MasterClock ??) + in_socket.WaitForConnection(); + out_socket.WaitForConnection(); + temp=1; + do + { + DSP::Clock::Execute(MasterClock, Fp/8); + + DSP::log << "MAIN" << DSP::e::LogMode::second << temp << endl; + temp++; + } + while (temp < 100); //(AudioIn.GetBytesRead() != 0); + + DSP::Clock::FreeClocks(); + DSP::log << DSP::e::LogMode::Error << "MAIN" << DSP::e::LogMode::second << "end" << endl; + //! \bug socket will be closed at application finish not at processing end + + return 0; +} diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_server_2.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_server_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..857fd796bffea7f69a5ed2aeb4e13c45fad72ca1 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/socket_server_2.cpp @@ -0,0 +1,76 @@ +/*! Digital Signal Processing Engine sockets usage example. + * Simple server application. + * \author Marek Blok + * \date 2010.02.09 + * \date updated 2021.01.18 + */ +#include <DSP_sockets.h> +#include <DSP_lib.h> +#include <DSP_modules_misc.h> + +int main(void) +{ + DSP::Clock_ptr MasterClock, MorseClock; + int temp; + long int Fp, Fp1; + + DSP::log.SetLogState(DSP::e::LogState::console | DSP::e::LogState::file); + DSP::log.SetLogFileName("log_file.log"); + + DSP::log << DSP::lib_version_string() << endl << endl; + + MasterClock = DSP::Clock::CreateMasterClock(); + +// DSP::u::WaveInput AudioIn(MasterClock, "DSPElib.wav", "."); +// Fp = AudioIn.GetSamplingRate(); + Fp = 8000; + DSP::u::DDScos AudioIn(MasterClock, false, 1.0, DSP::Float(1000*DSP::M_PIx2/Fp)); + + Fp1 = 1000; + MorseClock = DSP::Clock::GetClock(MasterClock, 1, Fp/Fp1); + DSP::u::MORSEkey MorseKey(MorseClock, 20, Fp1); + MorseKey.AddString("Digital Signal Processing Engine library"); + DSP::u::Zeroinserter MorseHold(MorseClock, Fp/Fp1, true); + MorseKey.Output("out") >> MorseHold.Input("in"); + + DSP::u::RealMultiplication Mul(2); + + AudioIn.Output("out") >> Mul.Input("in1"); + MorseHold.Output("out") >> Mul.Input("in2"); + + // use server socket +// DSP::u::SocketOutput out_socket("0.0.0.0", false, 0x00000003); + string bind_address = "0.0.0.0:10000"; + DSP::u::SocketOutput out_socket(bind_address, false, 0x00000003); + out_socket.SetName(bind_address); + Mul.Output("out") >> out_socket.Input("in"); + + DSP::u::RawDecimator MorseDec(MorseClock, 5); + DSP::u::FileOutput WAVEfile("morse_key.wav", DSP::e::SampleType::ST_short, 1, DSP::e::FileType::FT_wav, Fp1/5); + MorseKey.Output("out") >> MorseDec.Input("in"); + MorseDec.Output("out") >> WAVEfile.Input("in"); + //DSP::u::AudioOutput AudioOut(Fp); + //Mul.Output("out") >> AudioOut.Input("in"); + + DSP::Component::CheckInputsOfAllComponents(); + DSP::Clock::SchemeToDOTfile(MasterClock, "socket_server_2.dot"); + + //! \bug Implement WaitForAllConnections(MasterClock ??) + out_socket.WaitForConnection(); + temp=1; + do + { + DSP::Clock::Execute(MasterClock, Fp/8); + + DSP::log << "MAIN" << DSP::e::LogMode::second << temp << endl; + temp++; + } + while (temp < 200); //(AudioIn.GetBytesRead() != 0); + + DSP::Clock::FreeClocks(); + + DSP::log << DSP::e::LogMode::Error << "MAIN" << DSP::e::LogMode::second << "end" << endl; + //! \bug socket will be closed at application finish not at processing end + + return 0; +} diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/sound_input.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/sound_input.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e15d363e1afee5af3f9895d1ae5731608e7b50b1 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/sound_input.cpp @@ -0,0 +1,60 @@ +/*! Digital Signal Processing Engine Sound capture usage example. + * \author Marek Blok + * \date 2021.05.13 + * \date updated 2021.01.18 + */ +#include <DSP_lib.h> + +#ifndef INCLUDE_DSPE_EXAMPLES +int main(void) +#else +#include "DSPE_examples.h" +int test_sound_input(void) +#endif // INCLUDE_DSPE_EXAMPLES +{ + DSP::Clock_ptr MasterClock, AudioInClock; + string tekst; + int temp; + long int Fp, Fp2; + + DSP::log.SetLogState(DSP::e::LogState::console | DSP::e::LogState::file); + DSP::log.SetLogFileName("log_file.log"); + + DSP::log << DSP::lib_version_string() << endl << endl; + DSP::log << "Sound input example" << endl; + + MasterClock=DSP::Clock::CreateMasterClock(); + + DSP::u::WaveInput WaveIn(MasterClock, "DSPElib.wav", "."); + Fp = WaveIn.GetSamplingRate(); + + DSP::u::AudioOutput AudioOut(Fp); + + WaveIn.Output("out") >> AudioOut.Input("in"); + + Fp2 = 8000; + long Fp_gcd = DSP::f::gcd(Fp, Fp2); + AudioInClock=DSP::Clock::GetClock(MasterClock, Fp2 / Fp_gcd, Fp / Fp_gcd); + DSP::u::AudioInput AudioIn(AudioInClock, 8000, 1); + DSP::u::FileOutput WaveOut("captured_sample.wav",DSP::e::SampleType::ST_short, 1, DSP::e::FileType::FT_wav, Fp2); + + AudioIn.Output("out") >> WaveOut.Input("in"); + + DSP::Component::CheckInputsOfAllComponents(); + DSP::Clock::SchemeToDOTfile(MasterClock, "sound_input.dot"); + + temp=1; + do + { + DSP::Clock::Execute(MasterClock, Fp/8); + + DSP::log << "MAIN" << DSP::e::LogMode::second << temp << endl; + temp++; + } + while (WaveIn.GetBytesRead() != 0); + + DSP::Clock::FreeClocks(); + DSP::log << DSP::e::LogMode::Error << "MAIN" << DSP::e::LogMode::second << "end" << endl; + + return 0; +} diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/source_block_example.cpp b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/source_block_example.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7c565b02288d11814947b6c4c41016ffe8898ae --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/examples/source_block_example.cpp @@ -0,0 +1,211 @@ +// ***************************************************** // +//! Generates constant value +/*! + * Inputs and Outputs names: + * - Output: + * -# "out" (real, complex or multivalued valued) + * -# "out.re" (real component)\n + * "out.im" (imag component) + * -# "out1", "out2", ... (real or complex) + * -# "out1.re", "out2.re", ... (real part) + * -# "out1.im", "out2.im", ... (complex part) + * - Input: none + */ +class DSP::u::Const : public DSP::Source +{ + private: + DSP::Float const_val; + DSP::Float_vector const_state; + + static bool OutputExecute_one(DSP::Source_ptr source, DSP::Clock_ptr clock=NULL); + static bool OutputExecute_many(DSP::Source_ptr source, DSP::Clock_ptr clock=NULL); + + public: + onst(DSP::Clock_ptr ParentClock, DSP::Float value); + Const(DSP::Clock_ptr ParentClock, + DSP::Float value_re, DSP::Float value_im); + Const(DSP::Clock_ptr ParentClock, DSP::Complex value); + Const(DSP::Clock_ptr ParentClock, + int NoOfInputs_in, DSP::Float_ptr values); + Const(DSP::Clock_ptr ParentClock, + int NoOfInputs_in, DSP::Complex_ptr values); + ~Const(void); +}; + + +// ***************************************************** // +// generates const values +/* + * Inputs and Outputs names: + * - Output: + * -# "out" (real, complex or multivalued valued) + * -# "out.re" (real component)\n + * "out.im" (imag component) + * -# "out1", "out2", ... (real or complex) + * -# "out1.re", "out2.re", ... (real part) + * -# "out1.im", "out2.im", ... (complex part) + * - Input: none + */ +DSP::u::Const::Const(DSP::Clock_ptr ParentClock, + DSP::Float value) + : DSP::Source(ParentClock) +{ + SetName("Const", false); + + SetNoOfOutputs(1); + //SetNoOfInputs(0,false); + DefineOutput("out", 0); + DefineOutput("out.re", 0); + + RegisterOutputClock(ParentClock); + + const_val = value; + const_state.clear(); + + OutputExecute_ptr = &OutputExecute_one; +} + +DSP::u::Const::Const(DSP::Clock_ptr ParentClock, + DSP::Float value_re, DSP::Float value_im) + : DSP::Source(ParentClock) +{ + SetName("Const", false); + + SetNoOfOutputs(2); + DefineOutput("out", 0, 1); + DefineOutput("out.re", 0); + DefineOutput("out.im", 1); + + RegisterOutputClock(ParentClock); + + const_val = 0.0; + + const_state.resize(2); + const_state[0] = value_re; + const_state[1] = value_im; + + OutputExecute_ptr = &OutputExecute_many; +} + +DSP::u::Const::Const(DSP::Clock_ptr ParentClock, + DSP::Complex value) + : DSP::Source(ParentClock) +{ + SetName("Const", false); + + SetNoOfOutputs(2); + DefineOutput("out", 0, 1); + DefineOutput("out.re", 0); + DefineOutput("out.im", 1); + + RegisterOutputClock(ParentClock); + + const_val = 0.0; + + const_state.resize(2); + const_state[0] = value.re; + const_state[1] = value.im; + + OutputExecute_ptr = &OutputExecute_many; +} + +DSP::u::Const::Const(DSP::Clock_ptr ParentClock, + int NoOfOutputs_in, DSP::Float_ptr values) + : DSP::Source(ParentClock) +{ + string tekst; + int ind; + vector<int> temp_int; + + SetName("Const", false); + + SetNoOfOutputs(NoOfOutputs_in); + temp_int = new int[NoOfOutputs_in]; + for (ind = 0; ind < NoOfOutputs_in; ind++) + { + tekst = "out" + to_string(ind+1); + DefineOutput(tekst, ind); + tekst = "out" + to_string(ind+1) + ".re"; + DefineOutput(tekst, ind); + + temp_int.push_back(ind); + } + DefineOutput("out", NoOfOutputs_in, temp_int.data()); + + RegisterOutputClock(ParentClock); + + const_val = 0.0; + const_state.resize(NoOfOutputs_in); + for (ind = 0; ind < NoOfOutputs_in; ind++) + { + const_state[ind] = values[ind]; + } + + OutputExecute_ptr = &OutputExecute_many; +} + +DSP::u::Const::Const(DSP::Clock_ptr ParentClock, + int NoOfOutputs_in, DSP::Complex_ptr values) + : DSP::Source(ParentClock) +{ + string tekst; + int ind; + vector<int> temp_int; + + SetName("Const", false); + + SetNoOfOutputs(2*NoOfOutputs_in); + temp_int = new int[2*NoOfOutputs_in]; + for (ind = 0; ind < NoOfOutputs_in; ind++) + { + tekst = "out" + to_string(ind+1); + DefineOutput(tekst, 2*ind, 2*ind+1); + tekst = "out" + to_string(ind+1) + ".re"; + DefineOutput(tekst, 2*ind); + tekst = "out" + to_string(ind+1) + ".im"; + DefineOutput(tekst, 2*ind+1); + + temp_int.push_back(ind); + } + DefineOutput("out", NoOfOutputs_in, temp_int.data()); + + RegisterOutputClock(ParentClock); + + const_val = 0.0; + const_state.resize(2*NoOfOutputs_in); + for (ind = 0; ind < NoOfOutputs_in; ind++) + { + const_state[2*ind] = values[ind].re; + const_state[2*ind+1] = values[ind].im; + } + + OutputExecute_ptr = &OutputExecute_many; +} + +DSP::u::Const::~Const(void) +{ + const_state.clear(); +} + +#define THIS_ ((DSP::u::Const *)source) +bool DSP::u::Const::OutputExecute_one(DSP::Source_ptr source, DSP::Clock_ptr clock) +{ + THIS_->OutputBlocks[0]->Execute_ptr( + THIS_->OutputBlocks[0], THIS_->OutputBlocks_InputNo[0], + THIS_->const_val, source); + + return true; +}; + +bool DSP::u::Const::OutputExecute_many(DSP::Source_ptr source, DSP::Clock_ptr clock) +{ + int ind; + + for (ind = 0; ind < THIS_->NoOfOutputs; ind++) + THIS_->OutputBlocks[ind]->Execute_ptr( + THIS_->OutputBlocks[ind], THIS_->OutputBlocks_InputNo[ind], + THIS_->const_state[ind], source); + + return true; +}; +#undef THIS_ diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/ALSA_support.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/ALSA_support.h new file mode 100644 index 0000000000000000000000000000000000000000..76183e4bbd33c100d5d7aff20282597ce57000e8 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/ALSA_support.h @@ -0,0 +1,75 @@ +/*! \file ALSA_support.h + * ALSA support header file + * + * \author Marek Blok + */ +//--------------------------------------------------------------------------- +#ifndef ALSA_support_H +#define ALSA_support_H + +/* Use the newer ALSA API */ +#define ALSA_PCM_NEW_HW_PARAMS_API + +/* All of the ALSA library API is defined in this header */ +#include <alsa/asoundlib.h> + +#include <DSP_types.h> // for types + +namespace DSP { + + class ALSA_object_t : public DSP::SOUND_object_t { + private: + snd_pcm_t *alsa_handle; + snd_pcm_hw_params_t *hw_params; + + //! open default PCM device and return 1 on success or negative error code + /*! stream_type = SND_PCM_STREAM_PLAYBACK or SND_PCM_STREAM_CAPTURE + */ + int open_alsa_device(snd_pcm_stream_t stream_type, int no_of_channels, unsigned int &sampling_rate); + void close_alsa_device(bool do_drain = false, bool use_log = false); + + void get_period_size(snd_pcm_uframes_t &frames, unsigned int &period_time); + snd_pcm_sframes_t pcm_writei(const void *buffer, snd_pcm_uframes_t &frames); + + public: + + //! log basic ALSA information + void log_driver_data(); + + unsigned int select_input_device_by_number(const unsigned int &device_number=UINT_MAX); + unsigned int select_output_device_by_number(const unsigned int &device_number=UINT_MAX); + + long open_PCM_device_4_output(const int &no_of_channels, int no_of_bits, const long &sampling_rate, const long &audio_outbuffer_size = -1); + long open_PCM_device_4_input(const int &no_of_channels, int no_of_bits, const long &sampling_rate, const long &audio_outbuffer_size = -1); + bool close_PCM_device_input(void); + bool close_PCM_device_output(void); + + //! returns true is the playback is on + bool is_device_playing(void); + //! initializes playback stopping + bool stop_playback(void); + //! returns true is the sound capture is on + bool is_device_recording(void); + //! returns true is the sound capture is on + bool stop_recording(void); + + //! \note values stored in float_buffer might be altered + long append_playback_buffer(DSP::Float_vector &float_buffer); + //! Starts sound capture + bool start_recording(void); + bool get_wave_in_raw_buffer(DSP::e::SampleType &InSampleType, std::vector<char> &wave_in_raw_buffer); + + //! Returns false if callbacks are not supported of recording + bool is_input_callback_supported(void); + + //! Returns false if callbacks are not supported of playback + bool is_output_callback_supported(void); + + //! object constructor + ALSA_object_t(); + ~ALSA_object_t(); + }; + +} + +#endif // ALSA_support_H diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_AudioMixer.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_AudioMixer.h new file mode 100644 index 0000000000000000000000000000000000000000..0d3096900b1b826027caf2ae12327806c57f1d51 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_AudioMixer.h @@ -0,0 +1,259 @@ +/*! \file DSP_AudioMixer.h + * AudioMixer header file + * + * \author Marek Blok + */ +//--------------------------------------------------------------------------- +#ifndef AudioMixerH +#define AudioMixerH + +#if __BORLANDC__ == 0x0520 + #define _ANONYMOUS_STRUCT +#else +#endif + +#ifdef WIN32 + #include <windows.h> + #include <mmsystem.h> +#else + #define DWORD unsigned int + #define UINT unsigned int + #define MAXPNAMELEN 256 + + //! \TODO to be removed/replaced with linux specific implementation + #define WAVE_MAPPER ((UINT)-1) + +#endif + +#include <string> +using namespace std; + +//--------------------------------------------------------------------------- +#include <DSP_setup.h> +//--------------------------------------------------------------------------- + +namespace DSP { + const int AM_MasterControl = -1; + const int AM_PCMwaveFile = -2; + const int AM_PCMwaveFileON = -2; + const int AM_PCMwaveFileOFF = -3; + + namespace e { + enum struct AM_MutedState { + MUTED_INACTIVE = -1, + MUTED_YES = 1, MUTED_NO = 0 + }; + } +} + +class TAudioMixer +{ + private: +#ifdef WIN32 + static UINT WaveInCaps_size; + static std::vector<WAVEINCAPS> WaveInCaps; + static UINT WaveOutCaps_size; + static std::vector<WAVEOUTCAPS> WaveOutCaps; +#endif // WIN32 + + public: + static string GetWaveInDevName(UINT DevNo=WAVE_MAPPER ); + static string GetWaveOutDevName(UINT DevNo=WAVE_MAPPER ); + + bool MixerSupported; + //! true if there is global mixer or multiplexer for input lines + bool InputMixer_support; + + static const string PCMwaveFileName; + + static const DWORD Types[]; + static const string TypesNames[]; + static const string ComponentNames[]; + static const DWORD ComponentTypes[]; + +// AnsiString MixerName; + string Input_MixerName; + string Output_MixerName; + string Input_Output_MixerName; + + int Mixer_InputLinesNumber; //! Number of input lines supported by soundcard + + #ifdef WIN32 + MMRESULT rs; + + UINT MixersNumber; //Number of available mixers + UINT WaveInNumber; //Number of wave in audio devices + UINT WaveOutNumber; //Number of wave out audio devices + HMIXER hMixer_out; //Handler of the opened output mixer + HMIXER hMixer_in; //Handler of the opened input mixer + + // INPUTS + MIXERLINE MixerLineWAVEIN; //WAVEIN line currently in use + MIXERCONTROL MixerControlWAVEIN; //Main Mixer control for WAVEIN line + MIXERCONTROL MixerControlWAVEIN_VOLUME; //Main Mixer volume control for WAVEIN line + bool MixerControlWAVEIN_VOLUME_supported; + MIXERCONTROL MixerControlWAVEIN_MUTE; //Main Mixer MUTE control for WAVEIN line + bool MixerControlWAVEIN_MUTE_supported; + + //Number of items: MixerControlWAVEIN.cMultipleItems + std::vector<MIXERCONTROLDETAILS_LISTTEXT> MixerControlDetailsWAVEIN_LISTTEXT; + //Details for WAVEIN mixer control attached lines (sources) names and IDs (dwParam1) + std::vector<MIXERLINE> MixerLinesWAVEIN; //pointer for lines of WAVEIN sources + DWORD MixerLinesWAVEIN_MAXcChannels; + std::vector<MIXERCONTROL> MixerControlsWAVEIN_VOLUME; //pointer for controls for WAVEIN sources + std::vector<bool> MixerControlsWAVEIN_VOLUME_supported; //pointer table with entries indicating if volume control is supported + std::vector<MIXERCONTROL> MixerControlsWAVEIN_MUTE; //pointer for controls for WAVEIN sources + std::vector<bool> MixerControlsWAVEIN_MUTE_supported; + + + + // OUTPUTS + bool MixerSupportedOUT; + MIXERLINE MixerLineOUT; //output mixer master line + MIXERCONTROL MixerControlOUT_VOL; //Main Mixer volume control for output line + MIXERCONTROL MixerControlOUT_MUTE; //Main Mixer MUTE control for output line + + //Number of items: MixerLineOUT.cConnections + // MIXERCONTROLDETAILS_LISTTEXT *MixerControlDetailsOUT_LISTTEXT; + //Details for output mixer control attached lines (destinations) names and IDs (dwParam1) + std::vector<MIXERLINE> MixerLinesOUT; //pointer for lines of outputs + DWORD MixerLinesOUT_MAXcChannels; + std::vector<MIXERCONTROL> MixerControlsOUT_VOL; //pointer for controls for outputs volume + std::vector<bool> MixerControlsOUT_VOL_supported; + std::vector<MIXERCONTROL> MixerControlsOUT_MUTE; //pointer for controls for outputs MUTE + std::vector<bool> MixerControlsOUT_MUTE_supported; + + + //Memorized + bool Memorized_WAVEIN_MasterState[1]; + double Memorized_WAVEIN_MasterVolume[1]; + std::vector<MIXERCONTROLDETAILS_BOOLEAN> Memorized_ControlWAVEIN_BOOLEAN; //Memorized ControlWAVEIN state + std::vector<MIXERCONTROLDETAILS_UNSIGNED> Memorized_ControlWAVEIN_UNSIGNED; //Memorized source lines volume values + + #endif + + DSP::e::AM_MutedState Memorized_OUT_MasterState[2]; + double Memorized_OUT_MasterVolume[2]; + std::vector<DSP::e::AM_MutedState> Memorized_OUT_LinesStates; + std::vector<double> Memorized_OUT_LinesVolumes; + + bool MixerSettingsMemorized_WAVEIN; + bool MixerSettingsMemorized_OUT; + + static const string GetMixerControlType(DWORD dwControlType); + static const string GetMixerComponentType(DWORD dwComponentType); + + bool PCMwaveFileActive; + double PCMwaveFileActiveValue; + public: + //! Opens mixer to use with selected WaveIn and WaveOut devices + /*! WaveInDevNo - waveIn device number + * WaveOutDevNo - waveOut device number + */ + TAudioMixer(UINT WaveInDevNo = 0, UINT WaveOutDevNo = 0); + ~TAudioMixer(void); + +// void TestInfo(TStrings *Lines); + +// AnsiString GetMixerName(void); + string GetMixerName(void); + + //! Returns empty string on failure + string GetSourceLineName(int ind); + DWORD GetSourceLineType(int ind); + int GetNumberOfSourceLines(void); + + //! Returns empty string on failure + string GetDestLineName(int ind); + DWORD GetDestLineType(int ind); + int GetNumberOfDestLines(void); + + int GetActiveSourceLine(void); + void SetActiveSourceLine(int ActiveNo); + void SetActiveSourceLine(string ActiveName); + void SetSourceLineState(int LineNo, bool IsActive); + //! gets active source line volume + /*! - returns vol in range [0, 1] on success + * - returns -1.0 if failed + * . + */ + double GetActiveSourceLineVolume(void); + //! gets given source line volume + /*! - LineNo + * - AM_PCMwaveFile - set gain factor for wave file input + * - AM_MasterControl - set input master volume + * - 0..NoOfSourceLines-1 - set volume for given input + * . + * - returns vol in range [0, 1] on success + * - returns -1.0 if failed + * . + */ + double GetSourceLineVolume(int LineNo); + bool GetSourceLineState(int LineNo); // SELECTED : ON/OFF + //! sets active source line volume + /*! + * - vol in range [0, 1] + * - Returns true on success + * . + */ + bool SetActiveSourceLineVolume(double Vol); + //! sets source line volume + /*! + * - vol in range [0, 1] + * - LineNo + * - AM_PCMwaveFile - set gain factor for wave file input + * - AM_MasterControl - set input master volume + * - 0..NoOfSourceLines-1 - set volume for given input + * . + * - Returns true on success + * . + */ + bool SetSourceLineVolume(int LineNo, double Vol); + + //! Channel: + /*! - "-1" - is any ON + * - "0" - is left ON + * - "1" - is right ON + */ + DSP::e::AM_MutedState GetDestLineState(int LineNo, int Channel = -1); // 0/1 - MUTE : ON/OFF; -1 - unavailable +// bool SetDestLineState(int LineNo, bool IsMuted); + bool SetDestLineState(int LineNo, DSP::e::AM_MutedState IsMuted_Left, DSP::e::AM_MutedState IsMuted_Right=DSP::e::AM_MutedState::MUTED_INACTIVE); +// void SetDestLineState(char *LineName, bool IsMuted); + //! Channel: + /*! - "-1" - mean value + * - "0" - left channel + * - "1" - right channel + * + * Line: + * "-1" - master volume + * "0","1"... output lines + * + * returns: + * - < 0 on error + * - -2.0 if volume control is not supported for given line + * . + */ + double GetDestLineVolume(int LineNo, int Channel = -1); // 0/1 - MUTE : ON/OFF +// bool SetDestLineVolume(int LineNo, double Vol); + //! Sets destination line volume + /*! + * - Vol_Left, Vol_Right in range [0, 1] + * - LineNo + * - AM_PCMwaveFile - set gain factor for wave file input + * - AM_MasterControl - set input master volume + * - 0..NoOfSourceLines-1 - set volume for given input + * . + * - Returns true on success + * . + */ + bool SetDestLineVolume(int LineNo, double Vol_Left, double Vol_Right=-1.0); + + void MemorizeMixerSettings_WAVEIN(void); + void ForgetMixerSettings_WAVEIN(void); + void RestoreMixerSettings_WAVEIN(void); + + void MemorizeMixerSettings_OUT(void); + void ForgetMixerSettings_OUT(void); + void RestoreMixerSettings_OUT(void); +}; +#endif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_DOT.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_DOT.h new file mode 100644 index 0000000000000000000000000000000000000000..9a3aa1c39b594d30fff5d28e1b8055a09091179d --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_DOT.h @@ -0,0 +1,30 @@ +/*! \file DSP_DOT.h + * DOT graph support + * + * \author Marek Blok + */ +//--------------------------------------------------------------------------- +#ifndef DSP_DOT_H +#define DSP_DOT_H + +#include <string> +#include <vector> + + +//! Main DSPElib namespace +namespace DSP { + //! DOT colors table + extern const std::vector<std::string> DOT_colors; + + //! DSPElib sub-namespace for enums definitions + namespace e { + enum struct DOTmode { + DOT_macro_unwrap = 0, //! draw separate macro component (ignore macro structure) + DOT_macro_wrap = 1, //! as component in parent DOT graph, allow for separate macro graph + DOT_macro_as_component = 2, //! never unwrap + DOT_macro_subgraph = 3, //! unwrap as subgraph in parent DOT graph + DOT_macro_inactive = -1, //! draw inactive + }; + } +} +#endif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_Fourier.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_Fourier.h new file mode 100644 index 0000000000000000000000000000000000000000..546c3c3c2484c6bb58bcbfb5c80672263dcc95c2 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_Fourier.h @@ -0,0 +1,68 @@ +/*! \file DSP_Fourier.h + * DSP_Fourier class header file + * + * \author Marek Blok + */ +//--------------------------------------------------------------------------- +#ifndef DSP_FourierH +#define DSP_FourierH + +//#include "complex.h"; +//--------------------------------------------------------------------------- +#include <DSP_setup.h> +//--------------------------------------------------------------------------- +#include <DSP_types.h> +//--------------------------------------------------------------------------- +namespace DSP { + class Fourier + { + private: + unsigned long K, K2; + DSP::Complex_vector fft; + DSP::Complex_vector cSin; + // DSP::Complex_vector cSinConj; + //// DSP::Complex_vector cSinFFT; + + std::vector <unsigned long> RevBitTable, FFTshift_RevBitTable; + + + bool IsFFT, isFFTshiftON; + unsigned long Kbit; + + unsigned long BitRev(unsigned long x, const unsigned long &s); + public: + void resize(const unsigned long &K); + //void resizeR(unsigned long K2); + + Fourier(void); + Fourier(const unsigned long &K); + ~Fourier(void); + + bool CheckIsFFT(const unsigned long &K); + void FFTshiftON(const bool &val); + + //! \warning probki table is used to store internal values so it will be overwritten + void FFT(const unsigned long &N, DSP::Complex_vector &probki); + //! \warning probki table is used to store internal values so it will be overwritten + void IFFT(const unsigned long &N, DSP::Complex_vector &probki); + + void absFFT(const unsigned long &N, DSP::Float_vector &abs_fft, const DSP::Complex_vector &probki); + void absFFT(const unsigned long &N, DSP::Float_vector &abs_fft, const DSP::Float_vector &probki, const DSP::Float_vector &probki_imag); + void absFFTR(const unsigned long &N, DSP::Float_vector &abs_fft, const DSP::Float_vector &probki, const bool &JustHalf = false); + void abs2FFT(const unsigned long &N, DSP::Float_vector &abs_fft, const DSP::Complex_vector &probki); + + void absDFT(const unsigned long &N, DSP::Float_vector &abs_fft, const DSP::Complex_vector &probki); + void absDFT(const unsigned long &N, DSP::Float_vector &abs_fft, const DSP::Float_vector &probki, const DSP::Float_vector &probki_imag); + void absDFTR(const unsigned long &N, DSP::Float_vector &abs_fft, const DSP::Float_vector &probki, const bool &JustHalf = false); + + //! DFT (if possible FFT radix-2 is used) + /*! \note probki_in and probki_out can point to the same buffer + * @param N + * @param probki_in + * @param probki_out + */ + void DFT(const unsigned long &N, const DSP::Complex_vector &probki_in, DSP::Complex_vector &probki_out); + }; +} + +#endif // DSP_FourierH diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_IO.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_IO.h new file mode 100644 index 0000000000000000000000000000000000000000..b0848916d3401e4460b65438e625451a64676fcd --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_IO.h @@ -0,0 +1,1178 @@ +//--------------------------------------------------------------------------- +/*! \file DSP_IO.h + * This is Input/Output DSP module header file. + * + * Module blocks providing input and output from external devices + * like hard drive or sound card. + * + * \todo fully integrate DSP::u::WaveInput with DSP::u::FileInput + * + * \author Marek Blok + */ +#ifndef DSP_IO_H +#define DSP_IO_H + +#include <string.h> +//#include <cmath> +#include <stdio.h> + +//#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__)) +//# define __WIN32__ +//#endif + +////#ifdef __CYGWIN__ +//#ifdef WIN32 +#if defined(WIN32) || defined(WIN64) + #include <WMM_support.h> +#else + #ifdef LINUX + //! \TODO adapt for linux + #include <ALSA_support.h> + + #else + #error NO WIN32 + #endif +#endif + +//--------------------------------------------------------------------------- +#include <DSP_setup.h> +//--------------------------------------------------------------------------- +#include <DSP_modules.h> +#include <DSP_types.h> +//--------------------------------------------------------------------------- + +//#define AUDIO_DEBUG_MESSAGES_ON +#define AUDIO_DEBUG_MESSAGES_OFF + +namespace DSP { + const unsigned long File_buffer_size = 8192; + const unsigned long DefaultSamplingFrequency = 8000; + + //! Reference sampling frequency for which buffer sizes are selected + const unsigned long ReferenceFs = 48000; + // (1024*4) for Fp=48000 ==> 85ms ==> 11,72 buffer per second + const unsigned long Reference_audio_outbuffer_size = (1024*4); //(1024*64) + const unsigned long Reference_audio_inbuffer_size = (1024*4); + + namespace e { + enum struct AudioBufferType {none=0, input=1, output=2}; + } + + //! Number of input buffers in DSP::u::AudioInput + const unsigned long NoOfAudioInputBuffers = 4; + //! Number of output buffers in DSP::u::AudioOutput + /*! with one spare buffer + * + * in this case its internal buffer + */ + const unsigned long NoOfAudioOutputBuffers = 3; + + //! DSPElib sub-namespace for special functions + namespace f { + unsigned long ReadCoefficientsFromFile(DSP::Float_vector &Buffer, unsigned long N, const string &FileName, const string &FileDir, DSP::e::SampleType type, unsigned long offset); + unsigned long ReadCoefficientsFromFile(DSP::Complex_vector &Buffer, unsigned long N, const string &FileName, const string &FileDir, DSP::e::SampleType type, unsigned long offset); + bool GetWAVEfileParams(const string &FileName, const string &FileDir, T_WAVEchunk_ptr WAVEparams); + //! Determines file type by filename extension + DSP::e::FileType FileExtToFileType(const string &filename); + + //! This function adds the ability to get wav file params before DSP::Block creation + /*! Returns false if the file cannot be opened. + * + * \ingroup load_func + */ + bool GetWAVEfileParams(const string &FileName, const string &FileDir, T_WAVEchunk_ptr WAVEparams); + + //! returns audio buffer size for given Fs based on reference values given for DSP::ReferenceFs + uint32_t GetAudioBufferSize(const unsigned long &SamplingFreq, const DSP::e::AudioBufferType &type); + + #ifdef WINMMAPI + //! Issues error message and returns true if error detected + bool AudioCheckError(MMRESULT result); + #endif + } + + //! Namespace for units' classes (components: blocks and sources) + namespace u { + class Vacuum; + + class AudioInput; + class AudioOutput; + + class FileInput; + class FileOutput; + class WaveInput; + + class InputBuffer; + class OutputBuffer; + } +} + +//! Reads coefficients from file. +/*! Reads N coefficients from file Filename (in directory DirName) + * to the Buffer.\n + * Values in file must be stored in given format (type). Function makes conversion + * from given format to DSP::Float format.\n + * File reading starts from given offset (in bytes) which allows for reading + * from mixed data type files. + * + * Function returns number of bytes read from file. + * + * Supported data types: + * - DSP::e::FileType::FT_uchar - 8bit unsigned char: out=(val-128)/128 (0x80) + * - DSP::e::FileType::FT_short - 16bit signed integer: out=val/32768 (0x8000) + * - DSP::e::FileType::FT_float - single precision (32bit) floating point + * + * \ingroup load_func + */ +unsigned long DSP::f::ReadCoefficientsFromFile(DSP::Float_vector &Buffer, unsigned long N, + const string &FileName, const string &FileDir, + DSP::e::SampleType type=DSP::e::SampleType::ST_float, + unsigned long offset=0); + +namespace DSP { + /*! \todo Add support for Sony Wave64 (.w64) + */ + class T_WAVEchunk + { + public: + char Type[4]; // "RIFF" + uint32_t size; // chunk size = file size - 8 (size of chunk header) + + char SubType[4]; // "WAVE" + + char FmtType[4]; // "fmt " + uint32_t Fmtsize; // 16 + extra bytes + + uint16_t wFormatTag; // Data encoding format: 1 - PCM + uint16_t nChannels; // Number of channels + uint32_t nSamplesPerSec; // Samples per second + uint32_t nAvgBytesPerSec; // Avg transfer rate = nSamplesPerSec*nBlockAlign; + uint16_t nBlockAlign; // Block alignment + uint16_t wBitsPerSample; // Bits per sample + + char DataType[4]; + uint32_t DataSize; // numbers if bytes of samples' data (without padding byte) + // note: data segment must be padded with 0 if it is not of even length + // END OF HEADER // + + uint32_t BytesRead; + int HeaderSize; + + bool WAVEinfo(FILE *hIn); + bool FindDATA(FILE *hIn); + + void PrepareHeader(uint32_t nSamplesPerSec_in = 8000, uint16_t nChannels_in = 1, uint16_t wBitsPerSample_in = 16); + bool WriteHeader(FILE *hOut); + bool UpdateHeader(FILE *hOut); + + T_WAVEchunk(void); + // zeruj stan + void clear(); + + friend bool DSP::f::GetWAVEfileParams(const string &FileName, const string &FileDir, T_WAVEchunk_ptr WAVEparams); + + private: + int strncmpi(const char* str1, const char* str2, int N); + }; + + + const unsigned long FLT_header_LEN = 8; + /*! DSP::e::FileType::FT_flt : floating point content file header + * - 3 B - file version (ubit24) + * - 1B - header version + * - 2B - sample type + * 0x00 0x0000 - sample_type = 'float'; sample_size = 4; + * 0x00 0x0001 - sample_type = 'uchar'; sample_size = 1; + * 0x00 0x0002 - sample_type = 'short'; sample_size = 2; + * 0x00 0x0003 - sample_type = 'int'; sample_size = 4; + * - 1 B - number of channels (uint8) + * - 4 B - sampling rate (uint32) + */ + class T_FLT_header + { + private: + unsigned char data[FLT_header_LEN]; + public: + // unsigned char version; 1B + unsigned char version(void); + void version(unsigned char val); + // unsigned short sample_type; 2B + unsigned short sample_type(void); + void sample_type(unsigned short val); + // unsigned char no_of_channels; 1B + unsigned char no_of_channels(void); + void no_of_channels(unsigned char val); + // unsigned int sampling_rate; 4B + unsigned int sampling_rate(void); + void sampling_rate(unsigned int val); + }; + + const unsigned long TAPE_header_LEN = 1388; + /*! DSP::e::FileType::FT_tape : tape file header + */ + class T_TAPE_header + { + public: + unsigned int TotalSize; // length of following header // actual header size + 4 + char Filename[256]; + char CFG_filename[256]; + + unsigned int SwRev; + unsigned int HwRev; + unsigned int file_pointer; + unsigned int TAPE_TYPE; + + unsigned int start_time; //time_t + unsigned int end_time; //time_t + + unsigned int TotalSamples; + unsigned int current_sample; + + //long long loop_start; + unsigned int loop_start_MSW; + unsigned int loop_start_LSW; + //long long loop_end; + unsigned int loop_end_MSW; + unsigned int loop_end_LSW; + unsigned int loop; + + unsigned int group_size_32; + unsigned int block_size; + unsigned int block_count; + unsigned int fifo_size; + + char comment[256]; + char misc[20]; + + unsigned int status; + int time_stamps; + + float central_frequency; + float cplx_datarate; + + unsigned char reserved[512]; + + public: + //! size of the TAPE file header + unsigned int header_size(void) + { return TotalSize + 4; }; + + //! always 2 <==> short // DSP::e::SampleType::ST_short + unsigned short sample_type(void) + { return 0x0002; }; + + //! no_of_channels always == 2 + unsigned char no_of_channels(void) + { return 2; }; + + //! \todo implement sampling rate detection + unsigned int sampling_rate(void) + { return 0; }; + void sampling_rate(unsigned int val); + }; +} + +//! Block for connecting loose outputs +/*! If there is output which we don't need, + * we can connect it to this block in order + * to avoid error messages about unconnected + * outputs. + * + * Inputs and Outputs names: + * - Input: none + * - Output: + * -# "in1", "in2", ... - real or complex + * -# "in1.re", "in2.re", ... - (real components)\n + * "in1.im", "in2.im", ... - (imag components if exist) + * -# "in" == "in1" + * -# "in.re" == "in1.re"\n + * "in.im" == "in1.im"\n + * + * \bug <b>2006.09.04</b> This block should not require any parameters. + * It should accept any number of output lines connected to its inputs. + * \todo Consider two versions + * -# with strict option working the same way like now + * -# relaxed, e.g. accepting any number of connections + * . + * + */ +class DSP::u::Vacuum : public DSP::Block +{ + private: + void Init(bool AreInputsComplex, unsigned int NoOfInputs); + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + Vacuum(unsigned int NoOfInputs=1); + Vacuum(bool AreInputsComplex, unsigned int NoOfInputs=1); + ~Vacuum(void); +}; + +//! Creates object for *.wav files reading +/*! \todo_later 24-bit wav-files + * + * OutputsNo - number of outputs (one channel per output) + * + * If file has more channels then zeros are set to excesive outputs\n + * If file has less channels then execive channels are discarded + * + * \note Supports reading 8-,16- and 32-bit PCM wave file + * Inputs and Outputs names: + * - Output: + * -# "out" - real, complex or multiple-components + * -# "out.re" - first channel (real component)\n + * "out.im" - second channel (imag component) + * -# "out1", "out2", ... - i-th channel input + * - Input: none + * + */ +class DSP::u::WaveInput : public DSP::File, public DSP::Source//: public CAudioInput +{ + private: + //FILE *hIn; + bool FileEnd; + DSP::T_WAVEchunk WAVEchunk; + string FileName; + string FileDir; + + uint32_t ReadBufferLen; // in bytes + std::vector<char> ReadBuffer; + uint32_t AudioBufferLen; // in bytes + unsigned int BufferIndex; + std::vector<DSP::Float> AudioBuffer; + bool ConvertionNeeded; + + //! Number of bytes to read remaining in file + uint32_t BytesRemainingInFile; + //! number of bytes read during last file access + uint32_t BytesRead; + + + unsigned int SegmentSize; + unsigned int SamplingRate; + + //! To be used in constructor + bool Init(void); + //! Closes opened WAV file + bool CloseFile(void); + //! Reads next file segment (returns number of samples read per channel) + uint32_t ReadAudioSegment(void); + + /*! if file has more channels then zeros are set to excesive outputs + * if file has less channels then execive channels are discarded + * + * \todo_later Do this on the pointer stored in the object to avoid recalculation after ReadAudioSegment + * + */ + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + public: + WaveInput(DSP::Clock_ptr ParentClock, + const string &FileName_in, const string &FileDir_in, + unsigned int OutputsNo=1); //just one channel + ~WaveInput(void); + + bool SetSkip(long long Offset); + + DSP::File_ptr Convert2File(void) + { return GetPointer2File(); }; + + //! returns number of bytes read during last file access + virtual unsigned long GetBytesRead(void); + + //! returns sampling rate of audio sample + virtual unsigned long GetSamplingRate(void); + +// void SourceDescription(TStringList *); +}; + + +// ***************************************************** // +// ***************************************************** // +//! Multichannel file input block - sample format can be specified +/*! Inputs and Outputs names: + * - Output: + * -# "out" - real, complex or multiple-components + * -# "out.re" - first channel (real component)\n + * "out.im" - second channel (imag component) + * -# "out1", "out2", ... - i-th channel input + * - Input: none + * + * Supported file formats: + * - DSP::e::FileType::FT_raw + * - DSP::e::FileType::FT_flt + * - DSP::e::FileType::FT_wav + * - DSP::e::FileType::FT_tape + * . + * + * DSP::e::SampleType: DSP::e::SampleType::ST_bit and DSP::e::SampleType::ST_bit_reversed give -1.0 & +1.0 values + */ +class DSP::u::FileInput : public DSP::File, public DSP::Source +{ + private: + DSP::e::SampleType SampleType; + //! detected no of channels written in file + unsigned int NoOfFileChannels; + + DSP::Float_vector Buffer; + unsigned long BufferIndex; + + unsigned long BytesRead; + unsigned long SamplingRate; + + // in bits (all channels together) + //unsigned int InputSampleSize; ==> moved to DSP::File + std::vector<uint8_t> RawBuffer; + + static bool OutputExecute_Dummy(OUTPUT_EXECUTE_ARGS); + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + // Variables storing headers + //! *.flt header + std::vector<DSP::T_FLT_header> flt_header; + //! *.tape header + std::vector<DSP::T_TAPE_header> tape_header; + //! *.wav header + std::vector<DSP::T_WAVEchunk> wav_header; + + bool CloseFile(void); + public: + /*! Opens new file. + * + * Can be used between calls to DSP::Clock::execute + * or in blocks' callbacks. + */ + bool OpenFile(const string &FileName, + DSP::e::SampleType sample_type=DSP::e::SampleType::ST_float, + DSP::e::FileType FILEtype = DSP::e::FileType::FT_raw, + unsigned int Default_NoOfFileChannels = 0); + + //! NoOfChannels - expected no of outputs (channels in input file) + /*! NoOfChannels == 0 - autodetect no of channels + */ + FileInput(DSP::Clock_ptr ParentClock, + const string &FileName, + unsigned int NoOfChannels = 1U, + DSP::e::SampleType sample_type=DSP::e::SampleType::ST_float, + DSP::e::FileType FILEtype = DSP::e::FileType::FT_raw + ); + ~FileInput(void); + + bool SetSkip(long long Offset); + + //! Returns pointer to the header class + /*! If no header data are available or + * no header of the required type is available + * NULL is returned. + * + * Usage: + * -# "*.wav" : x = GetHeader<T_WAVEchunk>(); + * -# "*.flt" : x = GetHeader<T_FLT_header>(); + * -# "*.tape" : x = GetHeader<T_TAPE_header>(); + * . + */ + template <class T> + T *GetHeader(const unsigned int &index = 0); + + DSP::File_ptr Convert2File(void) + { return GetPointer2File(); }; + //! returns number of bytes read during last file access + unsigned long GetBytesRead(void); + //! returns number of bytes read during last file access + unsigned long GetSamplingRate(void); + //! Returns raw sample size in bytes corresponding to given SampleType + /*! \note For SampleType = DSP::e::SampleType::ST_none returns internal raw sample size + * used in DSP::u::FileInput. + * + * \warning Sample size is given in bits and encloses all channels + */ + unsigned long GetSampleSize(DSP::e::SampleType SampleType = DSP::e::SampleType::ST_none); + + //! Returns raw buffer size in bytes needed for NoOfSamples samples. + /*! If NoOfSamples == 0 return allocated internal raw buffer size. + */ + unsigned long GetRawBufferSize(const unsigned long &NoOfSamples = 0); + //! Returns DSP::Float buffer size needed for SizeInSamples samples. + /*! If SizeInSamples == 0 return allocated internal DSP::Float buffer size. + * + * \note Returned value is NoOfSamples * NoOfChannels. + */ + unsigned long GetFltBufferSize(const unsigned long &NoOfSamples = 0); + + //! moves file pointer no_to_skip samples forward + long long SkipSamples(const long long &no_to_skip); + + //! Reads segment for file and stores it in the buffer + /*! \note Size of the segment read depends on the flt_buffer size. + * + * Returns number of read bytes. + */ + unsigned long ReadSegmentToBuffer( + //! Buffer where read data will be stored in DSP::Float format + /*! \note size == buffer_size * no_of_channels + */ + DSP::Float_vector &flt_buffer, + //!number of sample components leave free after each (multicomponent) sample + /*! eg. {re0, im0, {pad}, re1, im1, {pad}, ...} + */ + int pad_size = 0 + ); +}; + +//! Multichannel file output block - sample format can be specified +/*! Suports + * - raw files: file without header file_type=DSP::e::FileType::FT_raw + * - sample_type=DSP::e::SampleType::ST_float + * - sample_type=DSP::e::SampleType::ST_scaled_float + * - sample_type=DSP::e::SampleType::ST_uchar + * - sample_type=DSP::e::SampleType::ST_short + * - sample_type=DSP::e::SampleType::ST_int + * - sample_type=DSP::e::SampleType::ST_bit_text + * - sample_type=DSP::e::SampleType::ST_bit + * - sample_type=DSP::e::SampleType::ST_bit_reversed + * . + * - PCM *.wav files: file_type=DSP::e::FileType::FT_wav + * - 8-bit : sample_type=DSP::e::SampleType::ST_uchar + * - 16-bit : sample_type=DSP::e::SampleType::ST_short + * - 32-bit : sample_type=DSP::e::SampleType::ST_scaled_float + * . + * - *.flt files: file_type=DSP::e::FileType::FT_flt or DSP::e::FileType::FT_flt_no_scaling (can be read with "fileread.m" from "toolbox") + * - sample_type=DSP::e::SampleType::ST_float + * - sample_type=DSP::e::SampleType::ST_uchar + * - sample_type=DSP::e::SampleType::ST_short + * - sample_type=DSP::e::SampleType::ST_int + * . + * . + * \note Both *.wav and *.flt files make use of sampling_rate parameter. + * + * Inputs and Outputs names: + * - Output: none + * - Input: + * -# "in" - real, complex or multiple-components + * -# "in.re" - first channel (real component)\n + * "in.im" - second channel (imag component) + * -# "in1", "in2", ... - i-th channel input + * + * \note Bit stream output (DSP::e::FileType::FT_bit and DSP::e::FileType::FT_bit_reversed) + * '-1.0 -> bit 0' & '+1.0 -> bit 1' + * + * \note If file_type is DSP::e::FileType::FT_short or DSP::e::FileType::FT_uchar input signal is limited + * to the range <-1.0, +1.0> + * + * \note NoOfChannels cannot be larger then UCHAR_MAX (255) + * + */ +class DSP::u::FileOutput : public DSP::File, public DSP::Block +{ + private: + DSP::e::SampleType SampleType; + DSP::e::FileType FileType; + //! true if file type imposes no input scaling + bool FileType_no_scaling; + DSP::T_WAVEchunk WAV_header; + + //DSP::Float *Buffer; + unsigned long BufferIndex; + + // in bits (all channel together) + //unsigned int OutputSampleSize; ==> moved to DSP::File + std::vector<uint8_t> RawBuffer; + std::vector<uint8_t> TmpBuffer; + + enum E_FlushBuffer {E_FB_default = 0, E_FB_raw = 1, E_FB_update_header = 2}; + E_FlushBuffer FlushBuffer_type; + + void FlushBuffer(void); + void raw_FlushBuffer(void); + + bool Open(const string &FileName, DSP::e::SampleType sample_type=DSP::e::SampleType::ST_float, + unsigned int NoOfChannels=1, DSP::e::FileType file_type=DSP::e::FileType::FT_raw, + long int sampling_rate = -1); + void Close(void); + + //! true if file must be reopen in current clock cycle + bool ReOpenFile; + string ReOpen_FileName; + DSP::e::SampleType ReOpen_SampleType; + DSP::e::FileType ReOpen_FileType; + unsigned long ReOpen_sampling_rate; + void PerformReOpen(); + + //! Just ignore inputs and process block and reopen signals + static void InputExecute_Dummy(INPUT_EXECUTE_ARGS); + static void InputExecute_float(INPUT_EXECUTE_ARGS); + static void InputExecute_scaled_float(INPUT_EXECUTE_ARGS); + static void InputExecute_uchar(INPUT_EXECUTE_ARGS); + static void InputExecute_uchar_no_scaling(INPUT_EXECUTE_ARGS); + static void InputExecute_short(INPUT_EXECUTE_ARGS); + static void InputExecute_short_no_scaling(INPUT_EXECUTE_ARGS); + static void InputExecute_int(INPUT_EXECUTE_ARGS); + static void InputExecute_int_no_scaling(INPUT_EXECUTE_ARGS); + static void InputExecute_bit_text(INPUT_EXECUTE_ARGS); + static void InputExecute_bit(INPUT_EXECUTE_ARGS); + static void InputExecute_blocked(INPUT_EXECUTE_ARGS); +// static void InputExecute(DSP::Block *block, int InputNo, DSP::Float value, DSP::Component_ptr Caller); + + //! true if file output is blocked + bool IsBlocked; + //! true if file output is to be blocked + bool BlockFile; + //! true if file output is to be unblocked + bool UnblockFile; + //! if source is blocked proper execute pointer is stored here + DSP::Block_Execute_ptr Stored_Execute_ptr; + //! Blocks or unblocks file output + void PerformBlock(bool block); + + public: + /*! Create object but not the file. + * \note Use ReOpen to create file. + */ + FileOutput(unsigned char NoOfChannels=1); + /*! \test constant inputs must be tested + */ + FileOutput(const string &FileName, + DSP::e::SampleType sample_type=DSP::e::SampleType::ST_float, + unsigned int NoOfChannels=1, + DSP::e::FileType file_type=DSP::e::FileType::FT_raw, + long int sampling_rate = -1); + ~FileOutput(void); + + bool SetSkip(long long Offset); + + //! returns number of bytes read during last file access + unsigned long GetBytesRead(void); + //! returns sampling rate of audio sample + unsigned long GetSamplingRate(void); + + //! Returns raw buffer size in bytes needed for NoOfSamples samples. + /*! If NoOfSamples == 0 return allocated internal raw buffer size. + */ + unsigned long GetRawBufferSize(const unsigned long &NoOfSamples = 0); + //! Returns raw sample size in bytes corresponding to given SampleType + /*! \note For SampleType = DSP::e::SampleType::ST_none returns internal raw sample size + * used in DSP::u::FileOutput. + * + * \warning Sample size is given in bits and encloses all channels + */ + unsigned long GetSampleSize(DSP::e::SampleType SampleType = DSP::e::SampleType::ST_none); + + //! Writes segment stores in buffer to file + /*! Returns number of written bytes. + * + * \note No all input sample types are supported + * + * \warning This function ignores file blocking state. + */ + unsigned long WriteSegmentFromBuffer( + //! Buffer where data which must be written is stored in DSP::Float format + /*! \note size == buffer_size * no_of_channels + */ + const DSP::Float_vector &flt_buffer, + //! number of samples to skip after each written sample + int skip = 0 + ); + + //! Flushes current buffer content to file + void Flush(void); + + //! Closes output file and opens new file with new parameters + /*! File must be closed when all input sample + * in the current cycle are ready. + * + * \note This function only marks output file to be reopened. + * All samples from current cycle will be stored in the old file. + */ + void ReOpen(const string &FileName, + DSP::e::SampleType sample_type=DSP::e::SampleType::ST_float, + DSP::e::FileType file_type=DSP::e::FileType::FT_raw, + long int sampling_rate = -1); + //! Call to block or unblock file output + /*! \param block if true samples are ignored instead of outputing to file + * + * \note similar result can be achieved with the help of signal activated clock + */ + bool BlockOutput(bool block = true); +}; + + +//! Creates object for recording audio +/*! + * OutputsNo - number of outputs (one channel per output) + * + * Inputs and Outputs names: + * - Output: + * -# "out" - real or complex + * -# "out.re" - first channel (real component)\n + * "out.im" - second channel (imag component if exists) + * -# "out1", "out2" - i-th channel output + * - Input: none + * + * \todo_later Implement this for Win32 case / Linux ??? + * + * Fixed <b>2005.07.23</b> No longer tries to process audio when audio object creation failed + */ +class DSP::u::AudioInput : public DSP::Source +{ + private: + DSP::T_WAVEchunk WAVEchunk; + #ifdef WINMMAPI + // HWAVEIN hWaveIn; + DSP::WMM_object_t snd_object; + #else + #ifdef ALSA_support_H + DSP::ALSA_object_t snd_object; + #else + #endif + #endif + + //! Called by SOUND_object_t when new data buffer is ready + bool SOUND_object_callback(const DSP::e::SampleType &InSampleType, const std::vector<char> &wave_in_raw_buffer); + + // //! Index of the buffer which is expected to filled next + // short NextBufferInd; + // //! Type of samples in WaveInBuffers + // DSP::e::SampleType InSampleType; + // #ifdef WINMMAPI + // std::vector<WAVEHDR> waveHeaderIn; + // #endif + // uint32_t WaveInBufferLen; // in bytes + // //! Buffers for audio samples prepared for playing + // std::vector<std::vector<char>> WaveInBuffers; + + //! size of the buffers used internally with WMM driver + uint32_t audio_inbuffer_size; + + //! in samples times number of channels + uint32_t InBufferLen; + //! Buffer for storing samples in DSP::Float format + DSP::Float_vector InBuffers[DSP::NoOfAudioInputBuffers]; + //! current read index in current InBuffer + unsigned int BufferIndex; + //! Index of the next buffer to fill + unsigned int EmptyBufferIndex; + //! Index of the buffer currently being read + unsigned int CurrentBufferIndex; + + +// int SegmentSize; + int SamplingFrequency; + + //! stores parent clock in case we must stall it for some time + DSP::Clock_ptr my_clock; + + //! To be used in constructor + /*! \bug <b>2006.08.13</b> when 8bit audio stream is created initial values should be 0x80 or 0x79 not 0x00 + * + * Fixed <b>2007.10.31</b> WaveIn device can now be selected, + * if WaveInDevNo is out of range WAVE_MAPPER is used. + */ + void Init(DSP::Clock_ptr ParentClock, + long int SamplingFreq, + unsigned int OutputsNo=1, //just one channel + char BitPrec=16, + unsigned int WaveInDevNo=UINT_MAX); // use WAVE_MAPPER + + // // indicates whether the recording started yet + // bool IsRecordingNow; + + // bool StartAudio(void); + // bool StopAudio(void); + // bool StopRecording; + //! (returns number of samples read per channel) + uint32_t GetAudioSegment(void); + + // static unsigned long Next_CallbackInstance; + // unsigned long Current_CallbackInstance; + // //! Addresses of audio object connected with CallbackInstances; + // /*! Current callback instance is also the index to this array + // */ + // static std::vector<DSP::u::AudioInput *> AudioObjects; + + // #ifdef WINMMAPI + // static void CALLBACK waveInProc_uchar(HWAVEIN hwi, UINT uMsg, + // uint32_t dwInstance, uint32_t dwParam1, uint32_t dwParam2); + // static void CALLBACK waveInProc_short(HWAVEIN hwi, UINT uMsg, + // uint32_t dwInstance, uint32_t dwParam1, uint32_t dwParam2); + // #endif + + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + public: +// DSP::u::AudioInput(DSP::Clock_ptr ParentClock); //SamplingFrequency=8000; + /*! Fixed <b>2007.10.31</b> WaveIn device can now be selected, + * if WaveInDevNo is out of range WAVE_MAPPER is used. + */ + AudioInput(DSP::Clock_ptr ParentClock, + long int SamplingFreq=8000, + unsigned int OutputsNo=1, //just one channel + char BitPrec=16, + unsigned int WaveInDevNo=UINT_MAX); // use WAVE_MAPPER + ~AudioInput(void); +// void SourceDescription(TStringList *); + + //! return No of free audio buffer + int GetNoOfFreeBuffers(void); + //! return No of all audio buffer + int GetNoOfBuffers(void); +}; + +//! Creates object for playing audio +/*! + * InputsNo - number of inputs (one channel per input) + * + * Inputs and Outputs names: + * - Output: none + * - Input: + * -# "in" - real or complex + * -# "in.re" - first channel (real component)\n + * "in.im" - second channel (imag component if exists) + * -# "in1", "in2" - i-th channel input + * + * \todo_later Implement this for Win32 case / Linux ??? + * + * Fixed <b>2005.07.01</b> problem when recording and playing audio + * simultaneously: output stream is interrupted until it synchronizes + * with input. The flaw of the current solution is increased output delay. + * + * Fixed <b>2005.07.23</b> No longer tries to process audio when audio object creation failed + */ +class DSP::u::AudioOutput : public DSP::Block +{ + private: + DSP::T_WAVEchunk WAVEchunk; + #ifdef WINMMAPI + //HWAVEOUT hWaveOut; + DSP::WMM_object_t snd_object; + #else + #ifdef ALSA_support_H + DSP::ALSA_object_t snd_object; + #else + #endif + #endif + + // //! Index of the buffer which must be used next time + // unsigned long NextBufferInd; + // //! Type of samples in WaveOutBuffers + // DSP::e::SampleType OutSampleType; + //#ifdef WINMMAPI + // std::vector<WAVEHDR> waveHeaderOut; + //#endif + // uint32_t WaveOutBufferLen; // in bytes + // //! Buffers for audio samples prepared for playing + // std::vector<std::vector<uint8_t>> WaveOutBuffers; + + //! size of the buffers used internally with audio driver + uint32_t audio_outbuffer_size; + + //! in samples times number of channels + uint32_t OutBufferLen; + //! Buffer for storing samples in DSP::Float format + DSP::Float_vector OutBuffer; + unsigned int BufferIndex; + + //! Prepares buffers for playing and sends it to the audio device + /*! saturation logic should be implemented */ + void FlushBuffer(void); + + //bool IsPlayingNow; + + // bool StartAudio(void); + // bool StopAudio(void); + // bool StopPlaying; + + // static unsigned long Next_CallbackInstance; + // unsigned long Current_CallbackInstance; + // //! Addresses of audio object connected with CallbackInstances; + // /*! Current callback instanse is also the index to this array + // */ + //static std::vector<DSP::u::AudioOutput *> AudioObjects; + + //! (returns number of samples read per channel) + uint32_t GetAudioSegment(void); + + //#ifdef WINMMAPI + // static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, + // uint32_t dwInstance, uint32_t dwParam1, uint32_t dwParam2); + //#endif + + void Init(unsigned long SamplingFreq, + unsigned int InputsNo=1, //just one channel + unsigned char BitPrec=16, + unsigned int WaveOutDevNo=UINT_MAX); + + /*! \test Test with constant inputs + * Fixed <b>2007.10.31</b> WaveOut device can now be selected, + * if WaveOutDevNo is out of range WAVE_MAPPER is used. + */ + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + AudioOutput(void); + //! DSP::u::AudioOutput constructor + /*! Fixed <b>2005.04.14</b> Cannot be initialized after previous object destruction + * Fixed <b>2007.10.31</b> WaveOut device can now be selected, + * if WaveOutDevNo is out of range WAVE_MAPPER is used. + * + * SamplingFrequency=8000; + */ + AudioOutput(unsigned long SamplingFreq, + unsigned int InputsNo=1, //just one channel + unsigned char BitPrec=16, + unsigned int WaveOutDevNo=UINT_MAX); + ~AudioOutput(void); + +// void SourceDescription(TStringList *); +}; + + +//************************************************************// +//! Source block providing input from the memory buffer +/*! Feeds samples from the buffer to the connected blocks. + * + * Inputs and Outputs names: + * - Input: none + * - Output: + * -# "out1", "out2", ... - real + * -# "out.re" == "out1" - (real component)\n + * "out.im" == "out2" - (imag component if exist) + * -# "out" - all outputs together + */ +class DSP::u::InputBuffer : public DSP::Source +{ + private: + //! callback function ID + unsigned int UserCallbackID; + //! callback notification function pointer + DSP::Notify_callback_ptr NotificationFunction_ptr; + //! Number of cycles between notifications + int NotificationsStep; + //! executes when notification or callback function must be processed + void Notify(DSP::Clock_ptr clock); + + //! actual size = BufferSize*sizeof(DSP::Float)*NoOfOutputs + long int BufferSize, BufferIndex; + //! data are internally stored in DSP::Float format + DSP::Float_vector Buffer; + + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + static bool OutputExecute_single_channel(OUTPUT_EXECUTE_ARGS); + static bool OutputExecute_cyclic(OUTPUT_EXECUTE_ARGS); + static bool OutputExecute_cyclic_single_channel(OUTPUT_EXECUTE_ARGS); + + public: + /*! NotificationsStep_in - Number of cycles between notifications + * - if NotificationsStep_in = -1 then NotificationsStep_in = BufferSize_in + * . + * + * If func_ptr != NULL then callback notification function is called. + * The calling block pointer and CallbackIdentifier are passed to this function. + * + * \note apart of standard notifications, notification function + * will be called twice: + * -# at the end of block contructor processing with CallbackIdentifier = (CallbackID_signal_start | UserCallbackID) + * -# at the beginning of block destuctor processing with CallbackIdentifier = (CallbackID_signal_stop | UserCallbackID) + * . + * + * + * BufferSize_in - size of the buffer in samples (each sample with NoOfChannels components) + * + * + * Cyclic: + * - DSP::e::BufferType::standard - fill with zeros when full + * - DSP::e::BufferType::cyclic - do not reset buffer content (will output the same content again) + * . + * \note buffer content might be overwritten in notification callback + * + * \warning CallbackIdentifier cannot be larger than CallbackID_mask. + */ + InputBuffer(DSP::Clock_ptr ParentClock, int BufferSize_in, + unsigned int NoOfChannels=1, DSP::e::BufferType cyclic=DSP::e::BufferType::standard, + int NotificationsStep_in = -1, DSP::Notify_callback_ptr func_ptr = NULL, + unsigned int CallbackIdentifier=0); + ~InputBuffer(void); + + //! copies source_size bytes from the source buffer to block's internal buffer + /*! Fixed <b>2005.03.17</b> Error in buffer size checking for multiple channels + */ + void WriteBuffer(void *source, long int source_size, DSP::e::SampleType source_DataType=DSP::e::SampleType::ST_float); +}; + +//! Block providing output to the memory buffer +/*! Writes input samples from the connected blocks to the memory buffer. + * + * Inputs and Outputs names: + * - Input: + * -# "in1", "in2", ... - real + * -# "in.re" - (real component)\n + * "in.im" - (imag component if exist) + * -# "in" - all inputs together + * - Output: + * - if Callback function is not defined + * -# none + * . + * - if Callback function is defined + * -# "out" - all output lines + * -# "out1", "out2", ... - 1st, 2nd, ... output line + * . + * . + * . + */ +class DSP::u::OutputBuffer : public DSP::Block, public DSP::Source +{ + private: + //unsigned int ind; + //! callback function ID + unsigned int UserCallbackID; + //! callback notification function pointer + DSP::Notify_callback_ptr NotificationFunction_ptr; + //! callback function pointer + DSP::Buffer_callback_ptr CallbackFunction_ptr; + //! Table for output values from callback function + DSP::Float_vector OutputsValues; + //! if true block must output samples values from OutputsValues table + bool OutputSamples_ready; + //! Variable storing the user data pointer from callback function + DSP::void_ptr UserData_ptr; + + + //! Number of cycles between notifications + /*! default: NotificationsStep == BufferSize + * if NotificationsStep > BufferSize + * { + * CyclesToSkip = BufferSize - NotificationsStep + * IsCyclic - does not have special sense + * } + * if NotificationsStep < BufferSize + * { + * CyclesToSkip = 0; + * if (IsCyclic == false) + * Buffer should be pushed instead of reset + * } + */ + long NotificationsStep; + //! executes when notification or callback function must be processed + void Notify(DSP::Clock_ptr clock); + + //! actual size = BufferSize*sizeof(DSP::Float)*NoOfInputs + long int BufferSize, BufferIndex; + //! data are internally stored in DSP::Float format + DSP::Float_vector Buffer; + //! Buffer wraps up if TRUE + bool IsCyclic; + //! Buffer stops when full if TRUE + /*! \note IsCyclic and StopWhenFull cannot be used together + */ + bool StopWhenFull; + + static void InputExecute(INPUT_EXECUTE_ARGS); + static void InputExecute_with_output(INPUT_EXECUTE_ARGS); + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + void Init(unsigned int BufferSize_in, unsigned int NoOfChannels, DSP::e::BufferType cyclic, int NotificationsStep_in); + public: + /*! If cyclic is true buffer is written continually + * after the last sample slot is filled, the first buffer slot will be + * filled. + * + * If cyclic is false, Buffer component will ignore input samples + * when all buffer slots are filled. Buffer must be reset by + * ReadBuffer function (see reset parameter) + * + * NotificationsStep_in - Number of cycles between notifications + * - if NotificationsStep_in = -1 then NotificationsStep_in = BufferSize_in + * . + * + * If func_ptr != NULL then callback notification function is called. + * The calling block pointer and CallbackIdentifier are passed to this function. + * + * \note BufferSize_in is the number of samples (each with NoOfInputs_in components) + * that can fit into buffer. Thus the actual buffer size is + * BufferSize_in * NoOfInputs_in * sizeof(DSP::Float). + * + * \note apart of standard notifications, notification function + * will be called twice: + * -# at the end of block constructor processing with CallbackIdentifier = (CallbackID_signal_start | UserCallbackID) + * -# at the beginning of block destructor processing with CallbackIdentifier = (CallbackID_signal_stop | UserCallbackID) + * . + * + * \warning CallbackIdentifier cannot be larger than CallbackID_mask. + * + * + */ + OutputBuffer(unsigned int BufferSize_in, unsigned int NoOfInputs_in=1, DSP::e::BufferType cyclic=DSP::e::BufferType::stop_when_full, + DSP::Clock_ptr ParentClock = NULL, int NotificationsStep_in = -1, + DSP::Notify_callback_ptr func_ptr = NULL, unsigned int CallbackIdentifier=0); + /*! Version with output lines. + * + * Callback function: + * void func(int NoOfInputs, DSP::Float_ptr InputSamples, + * int NoOfOutputs, DSP::Float_ptr OutputSamples, + * DSP::void_ptr *UserDataPtr, int UserDefinedIdentifier) + * \warning NoOfInputs will be set to the buffer inputs number, though + * InputSamples will always be NULL. + * \note Buffer MUST be read in callback function with reset set to <b>true</b>. + */ + OutputBuffer(unsigned int BufferSize_in, unsigned int NoOfInputs_in, DSP::e::BufferType cyclic, + DSP::Clock_ptr ParentClock, int NotificationsStep_in, unsigned int NoOfOutputs_in, + DSP::Buffer_callback_ptr func_ptr, unsigned int CallbackIdentifier=0); + //! Mixed block version with notifications controlled by given notifications clock + /*! \note NotificationsStep is determined from + * ParentClock and NotificationsClock relations. + * If NotificationsClock is not simply M times slower then + * ParentClock then NotificationsStep will be set -1. + * In that case DSP::u::OutputBuffer::ReadBuffer with reset set to -2 + * means the same as DSP::u::OutputBuffer::ReadBuffer with reset set to -1. + * + * \note If NoOfOutputs_in > 0 NotificationsClock has also the meaning of OutputClock. + */ + OutputBuffer(unsigned int BufferSize_in, unsigned int NoOfInputs_in, DSP::e::BufferType cyclic, + DSP::Clock_ptr ParentClock, DSP::Clock_ptr NotificationsClock, + unsigned int NoOfOutputs_in, DSP::Buffer_callback_ptr func_ptr, unsigned int CallbackIdentifier=0); + ~OutputBuffer(void); + + //! Copies dest_size bytes to the dest buffer from block's internal buffer + /*! + * If reset is non zero buffer state is reset after its content is copied. + * -# buffer type: DSP::e::BufferType::standard, DSP::e::BufferType::stop_when_full + * - reset == 0; - no buffer reseting + * - reset == -1; - full buffer reset + * - reset > 0; - free only reset slots in buffer + * - reset == -2; - free just NotificationsStep slots in buffer + * -# buffer type: DSP::e::BufferType::cyclic + * - reset == 0; - no buffer reseting + * - reset != 0; - buffer index reset. Buffer is filled from the beginning + * but buffer slots are not set to zero. + * . + * reset + * + * Returns number of samples read (not bytes !!!) + * If buffer is cyclic this depends on dest_size or BufferSize. + * If buffer is NOT cyclic this depends on number of samples in Buffer. + */ + unsigned long ReadBuffer(void *dest, long int dest_size, + long int reset=-1, DSP::e::SampleType dest_DataType=DSP::e::SampleType::ST_float); + //! low level access to the buffer + const DSP::Float_vector &AccessBuffer(void); + + //! returns number of samples already in the buffer + /*! \note Actual number of entries equals returned value + * times number of inputs + */ + unsigned long NoOfSamples(void); + + //! returns size of the buffer + /*! Returned value depends on mode + * - mode == 0: number of samples + * \note Actual number of entries equals returned value + * times number of inputs + * - mode == 1: number of DSP::Float entries + * - mode == 2: number of bytes + * . + */ + long int GetBufferSize(int mode = 0); +}; + + + + +#endif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_clocks.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_clocks.h new file mode 100644 index 0000000000000000000000000000000000000000..2e8955369a2ab397206ed238f461b161db7137c9 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_clocks.h @@ -0,0 +1,421 @@ +/*! \file DSPclocks.h + * This is DSP engine clocks management module header file. + * + * \author Marek Blok + */ +#ifndef DSPclocksH +#define DSPclocksH + +//--------------------------------------------------------------------------- +#include <DSP_setup.h> +//--------------------------------------------------------------------------- +#include <DSP_types.h> +#include <DSP_modules.h> + +#include <iostream> +#include <fstream> +#include <string.h> + +namespace DSP { + class Clock; + + namespace u { + class AudioInput; // required for friend class ::SocketInput + class SocketInput; // required for friend class ::SocketInput + } + + const unsigned long MAX_timeout_counter = 1000; +} + + +// ***************************************************** // +// ***************************************************** // +//! Class managing DSP algorithm clocks +/*! The main purpose of this class is to manage + * multifrequency DSP algorithms. + * + * Class supports independent and signal activated clocks, this allows for + * -# implementation of indepentend algorithms + * -# implementation of algorithms part working asynchronously, with clocks + * activated by signals + */ +class DSP::Clock +{ + friend class DSP::Block; + + public: + //! Returns Number of existing MasterClocks + static unsigned long GetNoOfMasterClocks(void) + { + return NoOfMasterClocks; + } + //! Returns Number of all existing Clocks + static unsigned long GetNoOfClocks(void) + { + unsigned long val; + + val = 0; + for (unsigned int ind = 0; ind < NoOfMasterClocks; ind++) + val += NoOfClocks[ind]; + return val; + } + //! Returns Number of existing Clocks linked with given Clock + /*! Returns number of all clocks with the same MasterClock ans given clock. + * Given clock and MasterClock are also counted. + */ + static unsigned long GetNoOfClocks(DSP::Clock_ptr clock) + { + return NoOfClocks[clock->GetMasterClockIndex()]; + } + + private: + //! Length of the clock cycle + /*! This variable stores number of the clock fundamental + * cycles separating consecutive excitations of + * the current clock. + */ + unsigned long cycle_length; + + //! Number of existing MasterClocks + static unsigned int NoOfMasterClocks; + //! Table of pointer to existing MasterClocks + static DSP::Clock_ptr *MasterClocks; + + //! Index to the clock controling this clock work (in MasterClock table) + /*! should be correct also for the MasterClock + */ + unsigned int MasterClockIndex; //DSP::Clock *MasterClock; + public: + //! returns MasterClockIndex + inline unsigned int GetMasterClockIndex(void) + { return MasterClockIndex; }; + private: + + //! ReferenceClock + DSP::Clock_ptr ParentClock; + //! ParentClock sampling frequency multiplier + /*! Sampling frequency of the current clock can be + * computed by multiplying by #L and dividing by #M sampling + * frequency of the master clock. + */ + long int L; + //! ParentClock sampling frequency divider + /*! Sampling frequency of the current clock can be + * computed by multiplying by #L and dividing by #M sampling + * frequency of the master clock. + */ + long int M; + + //! Function reculculating values of #DSP::Clock::cycle_length for all clocks with given MasterClock + /*! It is executed, for example, after creating or deleting + * of DSP::Clock object to update #DSP::Clock::cycle_length in each clock. + */ + static void UpdateCycleLengths(DSP::Clock_ptr RootParentClock); + + //! Algorithm's global cycle lengths (for each MasterClock) + static unsigned long *global_cycle_lengths; + //! Current discrete time of the algorithm (modulo global_cycle_legth) (for each MasterClock) + static unsigned long *current_discrete_times; + //! discrete times to next clocks activation in global cycles (for each MasterClock) + /*! \note table entry == 0 if unknown + */ + static unsigned long *global_discrete_times_to_next_step; + + //6) funkcja okre�laj�ca w oparciu o current_discrete_time + //oraz cycle_length ile czasu up�ynie do nast�pnego + //wywo�ania bie��cego zegara + unsigned long GetTimeToNextCycle(DSP::Clock_ptr CurrentMasterClock); + + //7) statyczna funkcja tworz�ca list� zegar�w, kt�re + //powinny si� uaktywni� w kolejnym cyklu (czyli tych + //dla kt�rych n0=GetTimeToNextCycle() zwraca najmniejsz� + //warto�� (po stworzeniu listy zwi�kszana jest warto�� + //current_discrete_time o n0) (for each MasterClock) + //! lista wskaza� na aktywne zegary + /*! rezerwowana na tyle ile jest zegar�w (ju� w konstruktorze DSP::Clock) + */ + static DSP::Clock_ptr* *ActiveClocksList; + //! Liczba wa�nych wpis�w w ActiveClocksLists (for each MasterClock) + static int *ActiveClocksListLength; + //! Returns pointer to list of clocks active in next cycle + /*! global_discrete_time_to_next_step - number of global cycles to next step + * + * Retuned table entries are only valid until FindNextActiveClocks + * is called next time for the same MasterClock. + * \warning Retuned table MUST not be freed by user, it will be released automaticaly. + */ + static DSP::Clock_ptr* FindNextActiveClocks(DSP::Clock_ptr CurrentMasterClock, + unsigned long &global_discrete_time_to_next_step); //(for each MasterClock) + //! List of clocks activated by signals in the current cycle (for each MasterClock) + /*! rezerwowana na tyle ile jest zegar�w (ju� w konstruktorze DSP::Clock) + */ + + static DSP::Clock_ptr* *SignalActivatedClocksList; + //! lists storing number of cycles of signal activated clock to process + /*! Values correspond to clocks in SignalActivatedClocksList + */ + static unsigned long * *SignalActivatedClocks_cycles_List; + //! Length of currently activated clocks (for each MasterClock) + static int *SignalActivatedClocksListLength; + + public: + //! Adds Signal activated clock to the list SignalActivatedClocksList + /*! MasterClockIndex - index of the MasterClock on list of which add ActivatedClock + * cycles - number of cycles of ActivatedClock to execute + */ + static void AddSignalActivatedClock(unsigned int MasterClockIndex, DSP::Clock_ptr ActivatedClock, unsigned long cycles = 1); + + //! Returns all (in ClocksList) clocks of the algorithm linked with ReferenceClock + /*! Generaly it means that returns all the clocks with the same MasterClock as ReferenceClock. + * + * ClockList - vector with list where clocks' pointers will be stored (appended) \n + * FindSignalActivatedClocks - if <b>true</b> function will look for + * signal activated clock (clocks with different MasterClock). + * + * + * Function returns actual number of stored clocks. + * In case of error: + * returns -1: no clock where found + */ + static long GetAlgorithmClocks(DSP::Clock_ptr ReferenceClock, + vector<DSP::Clock_ptr> &ClocksList, bool FindSignalActivatedClocks = false); + + private: + //8) Jednokierunkowa lista obiekt�w DSP::Clock + //! table of lists of DSP::Clock objects (for each MasterClock) + static DSP::Clock_ptr *First; + //! Number of ALL clocks (for each MasterClock) + static unsigned int *NoOfClocks; + //! Next clock but only with the same MasterClock + DSP::Clock_ptr Next; + + //9) tabela zarejestrowanych �r�de� DSP::Block for this clock + DSP::Source_ptr* SourcesTable; + //! number of sources regstered in SourcesTable + unsigned int NoOfSources; + //! true if coresponding source is SourcesTable is registered for notificatio0ns not for processing + DSP::Component_ptr* ComponentsNotifications_Table; + //! number of components registered in ComponentsNotifications_Table + unsigned int NoOfComponents; + + //10) Funkcj� do wyznaczania cycle_length + // u�ywane w UpdateCycleLengths() do wyznaczenia + // nowych warto�ci cycle_length + // oraz w GetClock() w celu weryfikacji czy ju� takiego + // zegara nie ma (for each MasterClock) + /*! L i M s� odpowiednio krotno�ci� interpolacji oraz decymacji + * wzgl�dem zegara o podanej d�ugo�ci cyklu (old_cycle) + * + * Funkcja zwraca nowa d�ugo�� cyklu (z uwzglednieniem L i M) oraz + * warto�� mno�nika przez jaki nale�a�oby przemno�y� wszystkie cycle zegar�w + * powi�zanych z MasterClock. + * + * Je�eli global_multiplier == 1 to napewno nie istnieje jeszcze zegar o + * takim cyklu o jaki si� zapytujemy + */ + static unsigned long CalculateNewCycle(//DSP::Clock_ptr MasterClock, + unsigned long old_cycle, + long int L, long int M, + // oraz wyprowadza mno�nik do old_cycle + // zapewniaj�cy, �e d�ugo�� cyclu wyj�ciowego + // jest warto�ci� ca�kowit� + unsigned long &global_multiplier); + + //Funkcja do wykorzystania tylko przez construktor klasy + void ClockInit(DSP::Clock_ptr ReferenceClock, + long int L_in, long int M_in, + unsigned int new_MasterClockIndex = UINT_MAX); + + //when true processing loop stops (for each MasterClock) + volatile static bool *Terminated; + //! source sets this when it still needs more time for external data to arrive + /*! e.g. audio card input + */ + volatile static bool *InputNeedsMoreTime; + friend class DSP::u::AudioInput; + friend class DSP::u::SocketInput; + + //! Processes all sources related to given clock: SourcesTable + /*! (returns false when not all sources could be processed) + */ + bool ProcessSources(int &NoOfProcessedSources); + //! Notify all components of this clock (all in ComponentsNotifications_Table) that new processign cycle started + void NotifyComponents(void); + //! Index of currently being processed source + unsigned int CurrentSource; + + //! Discrete time for the current clock + /*! Number of clock cycles from the beginning. + * Should be updated in DSP::Clock::Execute. + */ + uint32_t n; + + + private: + //! This will be MasterClock + /*! Creates clock without its MasterClock (will be added as MasterClock) + * this constructor should be called only from CreateMasterClock + */ + Clock(void); + //! This will be MasterClock + /*! This version reuses MasterClocks slot + */ + Clock(unsigned int new_MasterClockIndex); + public: + //DSP::Clock(unsigned int L_in, unsigned int M_in); + //! This will be descendant clock + Clock(DSP::Clock_ptr ReferenceClock, long int L_in, long int M_in); + //! Initiates new clock group (signal activated) synchronous with ReferenceClock + Clock(DSP::Clock_ptr ReferenceClock); + + //! removes clock and frees its structures + /*! Also takes care of MasterClocks list if MasterClock is removed. + */ + ~Clock(); + + +//?? Maybe clock's offset should also be used + //! Creates new independent MasterClock + static DSP::Clock_ptr CreateMasterClock(void); + + private: + //! Released alocated memory and all annotations about given MasterClock + static void ReleaseMasterClock(unsigned int MasterClockIndex); + //! Selects new clocks as master clock + /*! Invoked from DSP::Clock::ReleaseMasterClock + */ + static void SetAsNewMasterClock(DSP::Clock_ptr new_master); + + public: +// // Return pointer to the clock which is L/M +// // times faster than MasterClock (if necessary create it) +// static DSP::Clock_ptr GetClock(long L=1, long M=1); + // Returns pointer to the clock which is L/M + // times faster than *ParentClock + static DSP::Clock_ptr GetClock(DSP::Clock_ptr ParentClock, long L, long M); + //! Free all clocks + static void FreeClocks(void); + //! Free all clocks with the same MasterClock as ReferenceClock + /*! \note In case of signal activated asynchronous clocks + * Reference clock must be aquired manualy using GetClock + * and freed separately. + */ + static void FreeClocks(DSP::Clock_ptr ReferenceClock); + + //! List all registered components + /*! This is for safety precautions to indicate if any components + * are still registed when we want to call FreeClocks + * + * \warning This function works only in DEBUG mode + */ + static void ListComponents(void); + //! Lists all components (if list_outputs == true also lists components outputs) + static void ListOfAllComponents(bool list_outputs = false); + //! List all components registered with given MasterClock + /*! This is for safety precautions to indicate if any components + * are still registed when we want to call FreeClocks + */ + static void ListComponents(DSP::Clock_ptr MasterClock); + + private: + //Register and Unregister given Source block to this clock + //!Register given Source block to this clock + /*! Appends given source to the list in DSP::Clock::SourcesTable, + * but first checks whether source isn't already registered + */ + bool RegisterSource(DSP::Source_ptr Source); + //!Register given Component for notifications to this clock + bool RegisterNotification(DSP::Component_ptr Component); + friend void DSP::Source::RegisterOutputClock(DSP::Clock_ptr OutputClock, unsigned int output_index); + friend void DSP::Component::RegisterForNotification(DSP::Clock_ptr NotifyClock); + + //! Unregister source from the clock list + static bool UnregisterSource(DSP::Clock_ptr SourceClock, DSP::Source_ptr Source); + friend void DSP::Source::UnregisterOutputClocks(void); + //! Unregister component from the clock notification list + static bool UnregisterNotification(DSP::Clock_ptr NotificationClock, DSP::Component_ptr Component); + friend void DSP::Component::UnregisterNotifications(void); + + public: + //!Main processing loop (version 2) + /*! if NoOfCyclesToProcess != 0 <- processing + * only NoOfCyclesToProcess cycles, otherwise runs in infinitive loop. + * + * ReferenceClock - clock to which NoOfCyclesToProcess refers + * + * Function DSP::Clock::Execute can be called + * several times in a row to continue processing. + */ + static unsigned long Execute(DSP::Clock_ptr ReferenceClock, + unsigned long NoOfCyclesToProcess=0, + bool ReferenceClock_is_signal_activated=false); + + public: + //!Saves scheme information of the algorithm to DOT-file + /*! ReferenceClock - one of the clocks associated with + * the algorithm which we want to store in + * DOT-file format. + * + * \note Compile file with dot. For example "dot -Tgif filename.dot -ooutput.gif". + * See http://www.graphviz.org. + * + * \note This function is inactive in release mode. + * + */ + static void SchemeToDOTfile(DSP::Clock_ptr ReferenceClock, + const string &dot_filename, + DSP::Macro_ptr DrawnMacro = NULL); + + #ifdef __DEBUG__ + private: + //!Saves components information to m-file + /*! For all components linked with this clock info is stored + * in dot-file format. Called from DSP::Clock::SchemeToMfile + */ + bool ClockComponentsToDOTfile(std::ofstream &m_plik, + vector<bool> &ComponentDoneTable, long max_components_number, + vector<bool> &UsedMacrosTable, vector<DSP::Macro_ptr> &MacrosList, + vector<bool> &UsedClocksTable, vector<DSP::Clock_ptr> &ClocksList, + DSP::Macro_ptr DrawnMacro); + bool ClockNotificationsToDOTfile(std::ofstream &dot_plik, + vector<bool> &ComponentDoneTable, long max_components_number); + //bool *UsedClocksTable, DSP::Clock_ptr *ClocksList, long clocks_number); + #endif + + private: + //! clock's sampling rate + /*! Default value for MasterClock is 1.0 [Sa/s] + */ + long double SamplingRate; + //! global sampling rate for clock's family (< 0.0 if not set) + long double GlobalSamplingRate; + /*! Updates sampling rates for all clocks + * related to this clock, based on + * this clock SamplingRate + * + * must be called when: + * - new clock is created + * - sampling rate was changed + * . + */ + void UpdateSamplingRates(void); + //! Updates global sampling rate stored in clock based on sampling rates for all clocks in group + void UpdateGlobalSamplingRate(void); + + public: + //! Returns clock's sampling rate + /*! \note if sampling rate wasn't set for any of clocks, + * then result is based on MasterClocks default sampling rate. + */ + long double GetSamplingRate(void); + //! Changes clock's sampling rate + /*! \warning: Sampling rate for all clocks + * related to the same MasterClock will + * be updated. + */ + void SetSamplingRate(long double SR); +}; + +//extern DSP::Clock MasterClock; +/**************************************************/ +#endif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_lib.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_lib.h new file mode 100644 index 0000000000000000000000000000000000000000..bca9649159175e1d1ad39fa344562296aa81665b --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_lib.h @@ -0,0 +1,864 @@ +/*! \file DSP_lib.h + * DSP Engine library information header file. + * + * This is main header file. + * + * \author Marek Blok + */ + +#ifndef DSP_lib_H +#define DSP_lib_H + +#define DSP_VER_MAJOR 0 +#define DSP_VER_MINOR 20 +#define DSP_VER_BUILD 8 // !!! without zeroes before, else this will be treated as octal number +#define DSP_VER_YEAR 2021 +#define DSP_VER DSP_VER_MAJOR.DSP_VER_MINOR.DSP_VER_BUILD + +//#define WINVER 0x0A00 +//#define _WIN32_WINNT 0x0A00 + +#ifdef __DEBUG__ +#ifdef __DEBUG_LEAKAGE__ + #include "../nvwa/debug_new.h" +#endif +#endif + +#include <assert.h> +//--------------------------------------------------------------------------- +#include <DSP_setup.h> +//--------------------------------------------------------------------------- +#include <DSP_IO.h> +#include <DSP_clocks.h> +#include <DSP_modules2.h> +//#include <DSP_Fourier.h> +#include <DSP_AudioMixer.h> + +namespace DSP { + struct libver; + DSP::libver lib_version(void); + string lib_version_string(); +} + +/*! + * \addtogroup ver_data + */ +//! Structure containing DSP version information. SEE details for changes info... +struct DSP::libver +{ + unsigned char major; + unsigned char minor; + unsigned short build; +}; + +//! Returns DSP Engine library version information +/*! <b>Major library updates</b> + * + * \bug <b>2008.03.23</b> Check what will happen if all inputs are constant + * for blocks like DSP::u::PCCC. Those should work like sources and have clock defined. + * ConvertConst2Source <== checks whether all inputs are constant, + * defines block clock and adds to list of constant input blocks for given clock. + * \todo <b>2008.04.06</b> DSP::u::RawDecimator, DSP::u::SampleRateConverter - zaimplementowa� w wersji bez + * rejestracji jako źródÅ‚o (może nawet zaimplementować jako zwykÅ‚y blok przetwarzania) + * - może przyÅ›pieszyć przetwarzanie - mniej źródeÅ‚ do przeszukiwania + * \todo <b>2008.04.06</b> DSP::Component::CheckInputsOfComponents(DSP_clock_ptr) - checking + * only for components of given clock. Also implement version in DSP_clock like + * DSP_clock::ListOfComponents + * \todo <b>2008.04.10</b> Przejrze� bloczki wieloszybkosciowe i asynchroniczne. + * -# dla bloczk�w multirate + * -# decymatory w stosunku wymiernym -> przerobi� na zwyk�e processing blocks, + * nie wymagaj� obs�ugi za pomoc� zegara + * -# interpolatory w stosunku wymiernym -> musz� by� bloczkami typu mixed. + * Pytanie nale�y korzysta� z Notifications czy lepiej kontrol� + * kompletno�ci pr�bek wej�ciowych pozostawi� InputExecute i OutputExecute. + * \todo <b>2008.04.13</b> When wav file does not exist, something + * more then "Unsupported input sampling rate" should be stated + * for DSP::u::WaveInput + * + * \todo Update docs with info about usage of DSP_Clock_trigger + * + * \todo <b>2008.05.30</b> try if Multiplexer can be change into regular block + * instead of mixed one, output samples as soon as possible + * (implements as additional variant) + * + * \todo <b>2008.05.30</b> implement Demultiplexer as a source (additional variant) + * output all samples together (outputs must be delayed) + * + * \todo <b>2008.05.30</b> !!! implement offset clocks + * - normal clock but offset for some number of global cycles + * - needs rethinking of clock descent rules + * . + * + * \todo <b>2008.07.05</b> add macro into library documentation + * \todo <b>2008.07.09</b> add DSP::u::Quantizer into library documentation + * + * \bug <b>2008.09.29</b> Increase automatically named outputs range (now it is up to 999 output). + * In some case when working with buffer outputs it might be to little (see OFDM implementation). + * + * \bug <b>2008.09.29</b> DOT file generation needs buffer overflow fix. + * DSP::Component::GetComponentNodeParams_DOTfile fixed but there are + * more similar functions. + * + * \todo <b>2008.10.29</b> DSP::u::FIR introduce optimized InputExecute procedures instead of one universal + * + * \todo <b>2010.04.26</b> Integrate DSP::u::RealMultiplication in DSP::u::Multiplication as optimized implementation variant + * \todo <b>2010.04.26</b> Integrate DSP::u::LoopDelay in DSP::u::Delay as implementation variant + * \todo <b>2012.03.27</b> Test all variants of DSP::u::FIR + * \todo <b>2012.04.17</b> Check if DSP::u::FIR variant for I-FIR shaping filter is implemented on the basis + * of cyclic buffer and not based on memcpy + * + * \todo Add to the class DSP_clock + * - int RelatesToMasterClock[NoOfMasterClocks] + * . + * where index of MasterClock to which relates asynchronous clock will be stored. + * This information should be exploited in DSP_clock::FreeClocks(DSP_clock_ptr Reference clock) + * function to free related asynchronous clocks together with parent MasterClock. + * - find clocks related to ReferenceClocks's MasterClock + * - call FreeClocks for these clocks + * . + * + * \todo DSP_clock add relation to DSP_name + * - default name "%p" <- pointer + * - SetName <- adding user defined clock name + * - check if when DSP_clock is deleted all entries in + * InputClocks (?OutputClocks) of block are reset to NULL + * . + * + * \todo DSP_componet::Convert2Source() & DSP_componet::Convert2Block(). + * Add version DSP_componet::Convert2Source(bool ErrorWhenNULL) & DSP_componet::Convert2Block(bool ErrorWhenNULL) + * + * \todo ListComponents(DSP_clock_ptr, bool list_with_NULL) <- additionally list components with NULL clock + * + * \todo DSP_clock::ListComponents(NULL) <- list only all orphaned components + * + * \todo DSP_clock::ListComponents - print clock infos (pointer, L and M) + * + * \todo consider omitting InputClocks memory reservation in release mode + */ +DSP::libver DSP::lib_version(void); +//! Return DSP Engine library version information string. +string DSP::lib_version_string(); + +/* @} ver_data */ + + +// Examples list +/*! + * \example hello.cpp + * This example outputs to audio card first channel from DSPElib.wav file. + */ +/*! + * \example multirate.cpp + * This example implements simple multirate DSP algorithm. + */ +/*! + * \example callbacks.cpp + * This example implements output buffer with callback processing. + */ +/*! + * \example processing_block_example.cpp + * This code shows exemplary processing block class structure and implementation. + */ +/*! + * \example source_block_example.cpp + * This code shows exemplary source block class structure and implementation. + */ + + +/*! \mainpage Digital Signal Processing Engine Documentation + * + * <b>Digital Signal Processing Engine</b> 2005-2021 + * + * This project is licensed under GNU Lesser General Public License v2.1. + * \ref lib_license + * + * \section lib_lic_author Engine author + * The author of the <b>Digital Signal Processing Engine</b> library is Marek Blok. + * + * Author's email addresses: \par + * Marek.Blok@pg.edu.pl \n + * Marek.Blok@eti.pg.edu.pl + * + * <b>Digital Signal Processing Engine</b> is the library + * designed to help in easy and fast DSP multirate algorithms + * implementation as standalone computer applications. + * + * The main idea is to reduce algorithm implementation + * just to selecting DSP blocks, specifying blocks connections + * and in case of multirate or asynchronous + * algorithms, defining clocks relations. + * In order to make development process even easier + * and less error prone, in debug mode a range of problems, + * such as unconnected outputs and inputs or clocks mismatch, + * is detected and reported to the user. + * + * This library is the expansion of the concept of program + * <b>miCePS</b> (1993-1994) I've created during my last year of studies + * at Faculty of Electronics, Telecommunications and Informatics + * (www.eti.pg.gda.pl). The program allowed simple implementation + * of in-line signal processing with digital feedback loops + * defined in simple scripts with specifications of + * processing blocks and their connections. + * + * Since my graduation I work at Faculty of Electronics, + * Telecommunications and Informatics teaching mainly digital signal processing + * and doing research in that area. My main interest is in digital filters + * (mainly FIR) + * and multirate signal processing (mainly for communications applications), + * however programming is still my hobby. In teaching and research I usually + * use the MathWorks' MATLAB, however I'm not a fan of Simulink. + * After getting my PhD I've found some time to rethink the concept + * of <b>miCePS</b> and have come up with the library that allows + * for development and debugging of multirate in-line signal processing + * algorithms with digital feedback loops in stand alone applications. + * At that moment I think the library is at such a state that + * could be also useful for other people so I've decided to + * publish it. + * + * Main DSP Engine library advantages + * - scheme like implementations of algorithms + * - extensive debug info at development stage + * - simplicity of algorithm change and expansion (important at development stage) + * - openness (library frame work allows for fast addition of new blocks) + * - easy interfacing with Octave/MATLAB (with addons) + * . + * + * If you find this library useful I will be glad to hear about you experience from you. + * Generally, feel free to send me any propositions for improvements and new features. + * In the title line add [DSPElib]. \par + * e-mail: Marek.Blok@eti.pg.edu.pl + * + * Future plans + * - additional DSP blocks + * - built-in filter design routines + * - addon for DSP algorithms implementation based on scripts (like in <b>miCePS</b>) + * - DSP algorithm automatic C code generation + * - visual DSP algorithm presentation + * - visual DSP algorithm edition + * . + * + * \section lib_license Library lincensing information + * This project is licensed under GNU Lesser General Public License v2.1. + * \ref lib_license_text + * + * \section main_lib_users For library users + * - \ref lib_linking + * - \ref lib_use_alg + * - \ref DSP_units_list_page + * - \ref DSP_fnc_list_page + * - \ref lib_use_LOG + * - Audio input/output (::DSP::f::Sleep, ::DSP::f::SetSleepFunction and wxWidgets) + * - Audio mixer (TAudioMixer) + * - T_WAVEchunk + * - Examples + * - \link lib_use_hello_ex Hello world ;-) \endlink + * - \link lib_use_mult_ex Multirate algorithm \endlink + * - \link lib_use_callback_ex Output buffer callback \endlink + * - Asynchronous algorithm + * - Separate algorithms + * . + * - MATLAB addons + * . + * + * \section main_lib_info About library + * - \ref lib_license_text + * - \link ver_data Library version and major updates information \endlink + * - \ref DSP_units_list_page + * - \ref DSP_fnc_list_page + * . + * + * \section main_lib_devel For library addons developers + * - \ref devel_processing_block_ex + * - \ref devel_source_block_ex + * - \ref DSP::Block_page + * . + * + * \page lib_license_text DSPE library license + * This project is licensed under GNU Lesser General Public License v2.1. + * + * \include{doc} "../LICENSE" + * + * \page lib_linking Linking with Digital Signal Processing Engine (MinGW) + * + * Here you can find information about compiling and linking with + * <b>Digital Signal Processing Engine</b> MinGW (http://www.mingw.org) + * version. + * + * I use Eclipse (http://www.eclipse.org) with CDT (http://www.eclipse.org/cdt) + * as development platform and directories are selected for use with + * "Managed Make C++ Project". + * + * Linking options given below assume + * the following directory structure: + * \code + * .../workspace/project <<- user project directory + * .../workspace/project/_DSP_lib_minGW <<- Digital Signal Processing Engine directory + * \endcode + * + * \section lib_ln_cpp User's source file + * \code + * #include <DSP_lib.h> + * \endcode + * + * Library version can be checked using + * - ::DSP::lib_version function which returns DSP::libver structure + * - ::DSP::lib_version_string function which returns string with version and copyright + * information + * . + * + * \section lib_ln_base Linking in release mode + * + * \subsection lib_ln_comp Compiler options + * \par + * -DWIN32 \n + * \n + * -I../_DSP_lib_minGW/include \n + * -I../_DSP_lib_minGW/rls + * + * \subsection lib_ln_linker Linker options + * \par + * -L../_DSP_lib_minGW/rls \n + * \n + * -lwinmm \n + * -lDSP \n + * + * \section lib_ln_base_db Linking in debug mode + * + * \subsection lib_ln_comp_db Compiler options + * \par + * -DWIN32 \n + * \n + * -I../_DSP_lib_minGW/include \n + * -I../_DSP_lib_minGW/dbg + * + * \subsection lib_ln_linker_db Linker options + * \par + * -L../_DSP_lib_minGW/dbg \n + * \n + * -lwinmm \n + * -lDSP \n + * + * \note In debug mode \p __DEBUG__ preprocessing option is defined. + * + * \section lib_ln_base_wx Using wxWidgets with DSP Engine + * In several of my project to present in real time + * processing results I've used wxWidgets (http://www.wxwidgets.org) + * with OpenGL. + * \note This is only example at your actual needs might require different set of options. + * + * \subsection lib_ln_wx_comp Compiling wxWidgets with OpenGL enabled. + * + * \code + path=E:\mingw\bin;E:\msys\1.0\bin\;%path% + + mkdir build-yyyy_mm_dd + cd build-yyyy_mm_dd + sh ../configure --with-msw --disable-compat24 --with-opengl --disable-precomp-headers --enable-optimise --disable-shared --enable-sockets + make + * \endcode + * + * Linking options given below assume + * the following directory structure: + * \code + * .../workspace/_wxWidgets_2.6.3_minGW/lib <<- wxWidgets library directory + * .../workspace/_wxWidgets_2.6.3_minGW/include <<- wxWidgets include directory + * .../workspace/project <<- user project directory + * .../workspace/project/_DSP_lib_minGW <<- Digital Signal Processing Engine directory + * \endcode + * \subsection lib_ln_comp_wx Compiler options + * \par + * -D__WINDOWS__ \n + * -DHAVE_W32API_H \n + * -D__GNUWIN32__ \n + * -D__WXMSW__ \n + * \n + * -I../../_wxWidgets_2.6.3_minGW/lib/wx/include/msw-ansi-release-static-2.6 \n + * -I../../_wxWidgets_2.6.3_minGW/include + * + * \subsection lib_ln_linker_wx Linker options + * \par + * -L../../_wxWidgets_2.6.3_minGW/lib \n + * \n + * -lwx_msw_core-2.6 \n + * -lwx_base-2.6 \n + * -lwx_msw_gl-2.6 \n + * -ladvapi32 \n + * -lshell32 \n + * -lole32 \n + * -loleaut32 \n + * -lopengl32 \n + * -luuid \n + * -lglu32 \n + * -lcomctl32 \n + * \n + * -mwindows + * + * \page lib_use_alg Algorithm creation rules + * + * Algorithm creation rules index: + * - \ref alg_cr_stages + * - \ref alg_cr_clocks + * - \ref alg_cr_connect + * - \ref alg_cr_unconnected + * - \ref alg_cr_clearing + * - \ref alg_cr_consts + * - \ref alg_cr_feedback + * - \ref alg_cr_adv + * . + * + * \section alg_cr_stages Algorithm creation stages: + * -# The Master Clock creation, + * -# Algorithm blocks creation and connections definitions. + * At this stage additional clocks related to the Master Clock + * might be created, + * -# Algorithm execution, + * -# Deleting blocks, + * -# Freeing clocks. + * . + * \note Clocks might be freed before blocks deletion (e.g. if + * blocks are not created dynamically) but such situation should be + * generally avoided. + * + * \section alg_cr_clocks Algorithm clocks + * Processing of outputs in sources and mixed blocks is + * trigered at corresponding clock's cycle. This means that when + * such a block is created its clock must be defined. + * + * For each separate algorithm Master Clock must be created. + * If the algorithm is asynchronous or multirate, additional + * clocks related to Master Clock will be created. + * + * + * - <b>Master Clock</b> \n + * The first to do thing when new algorithm is defined is + * Master Clock creation. This is done by calling function + * DSP_clock::CreateMasterClock. This function returns + * Master Clock pointer (DSP_clock_ptr) which can be further used + * in sources or mixed blocks creation or in related clocks + * creation. + * \n \n + * - <b>Acquiring clocks related to Master Clock</b> \n + * Clock related to Master Clock working + * L/M times faster then Master Clock are created + * created automaticaly when multirate blocks are defined + * or can be also defined by user. + * - For asynchronous or multirate blocks DSP::Component::GetOutputClock + * function returns output clock. + * \warning This function should be used with care + * because in case of standard blocks, which does not create + * their output clocks automaticaly, this function might + * return NULL. Note that not at each DSP algorithm creation + * stage block's output clock can be resolved. + * - When clock in needed before multirate block is defined + * user can create it using DSP_clock::GetClock function. + * . + * \note Conversion using DSP_clock::GetClock + * is not possible between asynchrounous clocks. + * \n \n + * - <b>Signal activated clocks</b> \n + * In some situations two parts of the algorithm work asynchronously. + * For example in digital demodulators symbol sampling is not + * strictly related to the input clock. In such cases signal activated clocks + * must be used. To make use of such a clock several things must be taken care of + * -# Two asynchronous parts of the algorithm must be connected with special + * asynchronous blocks like: DSP::u::Hold, DSP::u::Farrow. + * -# The both parts must have separate master clocks. The signal activated clock + * must be generated using DSP_clock::CreateMasterClock (different from that for + * main algorithm part) or be related to this clock. + * -# Signal activated clock must be activated by special processing block + * DSP::u::ClockTrigger. + * . + * \n \n + * - <b>DSP algorithm execution</b> \n + * DSP algorithm processing is started using following functions: + * - \link DSP_clock::Execute DSP_clock::Execute(DSP_clock_ptr ReferenceClock, unsigned long NoOfCyclesToProcess) \endlink + * . + * One long algorithm execution can me split into several consecutive execute function executions + * allowing user to do something else during breaks, e.g. signals visualisation, spectral analysis, + * algorithm parameters update, checking finish conditions, etc. + * \note + * -# As ReferenceClock any clock related to Master Clock can used, not just Master Clock. + * -# If NoOfCyclesToProcess equals 0 or is unspecified algorithm will run in infinite loop. + * This can be usefull if DSP processing is run as a separate thread. + * . + * \n + * - <b>Freeing clocks</b> \n + * When processing is finished and blocks deleted, + * all clocks should also be deleted. There are two possibilities: + * -# DSP_clock::FreeClocks(void) function which deletes all clocks + * -# DSP_clock::FreeClocks(DSP_clock_ptr ReferenceClock) function which deletes all clocks + * related to ReferenceClock, e.g. all clocks with the same Master Clock + * as ReferenceClock. + * . + * \note In case of signal activated asynchronous clocks if + * DSP_clock::FreeClocks(void) canot be used + * Reference clock must be aquired manualy using DSP::Component::GetClock() + * get function and freed separately with + * DSP_clock::FreeClocks(DSP_clock_ptr ReferenceClock) function. + * + * + * + * \section alg_cr_connect Connecting blocks + * Connections between blocks can be defined using + * - bool operator>>( const DSP_output &output, const DSP_input &input ) + * - bool operator<<( const DSP_input &input, const DSP_output &output) + * - ::DSP::_connect_class::connect(DSP_output_ptr output, DSP_input_ptr input, bool AllowSplit) + * . + * + * In most situations <b>DSP::_connect_class::connect</b> function with AllowSplit == true + * (default behaviour) should be used to connect blocks output to other block's input. + * Several inputs can be connected using this function to the same output. + * + * <b>DSP::_connect_class::connect</b> function with AllowSplit == false can be only used + * to join unconnected output line to unconnected input line. This can help debug + * situations when several inputs are connected to single output. + * When output line must be connected to several input lines and <b>DSP::_connect_class::connect</b> + * with AllowSplit == false is used for the first connection, + * for consecutive connections <b>DSP::_connect_class::splitconnect</b> or + * <b>DSP::_connect_class::connect</b> with AllowSplit == true must be used. + * + * \note For obvious reasons it's not possible to connect several output lines + * to one input line. When such an attempt is detected in the DEBUG mode the + * appropriate error message is reported to LOG. + * + * Pointers defining output and input are obtained using + * - DSP::Component::Output(char *output_name) + * - DSP::Block::Input(char *input_name) + * . + * where block output/input is identified by its name (see \ref lib_use_hello_ex). + * Inputs and outputs names can be found in each block documentation + * (in detailed description). + * For example see DSP::u::Addition where you can find that quite often + * inputs can be addressed in more than one way. For example instead + * addressing complex input with "cplx_in1", you can access its + * real and imaginary parts separately using "cplx_in1.re" and + * "cplx_in1.im" names. + * + * \note Inputs and outputs are numbered from 1, e.g. "in1", "in2", ... + * (there is no "in0" input). + * + * + * \section alg_cr_unconnected Dealing with unconnected outputs + * In DEBUG mode DSP Engine will report unconnected outputs + * each time output sample is generated. This helps to detect + * situations when somthing has been forgotten. However, quite + * often you migth want to discard some of the output lines of + * blocks with more then one output line. The way to suppress + * error messages is to connect unneeded outputs to + * special block DSP::u::Vacuum. + * + * + * \section alg_cr_clearing Verification if all components have been deleted + * In general it is adviced to created processing blocks dynamically + * with C++ <b>new</b> operator. This means that when the processign is + * finished all blocks must be freed with <b>delete</b> operator. + * During algorithm creation process some of the blocks can be easily + * omitted at deletion stage. Therefore the functions DSP_clock::ListOfAllComponents + * and DSP_clock::ListComponents have been introduced to help user check + * if any of the blocks have been left behind. + * \note The best place to call DSP_clock::ListOfAllComponents or DSP_clock::ListComponents + * is just before freeing clocks (see \ref alg_cr_clocks). + * + * + * \section alg_cr_consts Constant inputs + * Some of the blocks allow to set constat value to the input + * instead of connecting some block's output to it. + * Use + * - DSP::Block::SetConstInput(char *input_name, DSP::Float value) + * function for real valued inputs + * - DSP::Block::SetConstInput(char *input_name, DSP::Float value_re, DSP::Float value_im) + * function for complex valued inputs. + * . + * In the following example only frequency of DDS will be changed + * during processing with amplitude and initial phase constant. + * \code + * DSP::u::DDScos SinGen(Clock1, true); + * SinGen.SetConstInput("ampl",1.0); // Set constant amplitude + * SinGen.SetConstInput("phase",0.0); // Initial phase set to zero + * DSP::_connect_class::connect(Freq.Output("out"), SinGen.Input("in")); + * \endcode + * + * + * \section alg_cr_feedback Feedback loops + * When creating DSP algorithm special care must be taken of + * feedback loops. Generally output cannot be directly connected + * to input so special blocks must be used. These blocks are + * called here mixed block because they work like a source + * but they have also inputs. + * + * Basic block for separating input form output in feedback loops + * is the delay block DSP::u::LoopDelay. Note that there is also + * DSP::u::Delay block but it cannot be used in the feedback loop. + * However DSP::u::Delay should be used in all other cases + * because it is implemented in more efficient way than + * DSP::u::LoopDelay. + * + * + * \section alg_cr_adv Advanced + * - DSP::Component vs DSP::Block and DSP::Source + * - DSP::Component::Convert2Block + * - DSP::Component::Convert2Source + * . + * . + */ +/*! + * \page lib_use_hello_ex Hello world example + * + * This example outputs to audio card first channel from DSPElib.wav file. + * + * \note It is better idea to dynamically create objects DSP::u::WaveInput + * and DSP::u::AudioOutput. + * + * \include hello.cpp + * + * + * \page lib_use_callback_ex Output buffer callback + * + * This example sends audio input to output buffer + * which sends out samples with optional spectrum inversion + * to the multiplexer. Then signal is demultiplexed. + * odd samples change sign (spectral inversion) and + * multiplexed again. Finally signal is send to audio output. + * + * \include callbacks.cpp + * + * + * \page lib_use_mult_ex Multirate algorithm example + * + * This example adds echo to the input audio. + * + * Input works with Fp1 = 22050 Sa/s. \n + * Output works with Fp2 = 8000 Sa/s. \n + * + * \warning Before running this example >>LPF_22050_8000.coef<< file + * must be generated in >>matlab<< subdirectory. This can be done with + * MATLAB script >>multirate_filters.m<<. + * + * \note Too make this example more sophisticated sampling + * rate conversion is done twice. First time for sound with echo and + * then again in echo loopback. + * + * Input: + * -# DSPElib.wav file + * -# soundcard + * -# chirp generator + * . + * + * \include multirate.cpp + * + * + * \page devel_processing_block_ex Processing block implementation example + * + * This example show processing block class construction and implementation. + * + * \include processing_block_example.cpp + * + * + * \page devel_source_block_ex Source block implementation example + * + * This example show source block class construction and implementation. + * + * \include source_block_example.cpp + * + * + * \page lib_use_LOG LOG functions and DEBUG info + * \section lib_LOG_setup Setting up LOG + * - DSP::log - default logstream object + * - DSP::logstream::SetLogState + * - DSP::logstream::GetLogState + * - DSP::E_LS_Mode + * - DSP::logstream::NoOfErrors + * - DSP::logstream::SetLogFileName + * - DSP::logstream::SetLogFunctionPtr + * - DSP::Message_callback_ptr + * . + * \section lib_LOG_dbg DEBUG info + * In DEBUG mode wide range of information about problems encountered + * during algorithm setup and running. For example: + * - attempt to connect to already used input + * - unconnected outputs + * - problems like attempt to connect real input to complex output, etc. + * - inputs' and outputs' clocks mismatch + * - can list all existing blocks (for example to check if there are some not deleted blocks after clean up process) + * . + * \section lib_LOG_usr User LOG messages + * - DSP::e::LogMode::Info, DSP::e::LogMode::Error, DSP::e::LogMode::first, DSP::e::LogMode::second + * - DSP::log << "Hello" << DSP::e::LogMode::second << "This is echo !!!" << endl; + * - DSP::log << DSP::e::LogMode::Error << "MAIN" << DSP::e::LogMode::second << "end" << endl; + * . + * - DSP::e::LogMode::pause, DSP::e::LogMode::pause_off + * - DSP::log << DSP::e::LogMode::pause << "Finished SolveMatrix test" << endl; + * . + * . + * \section lib_LOG_wx Working with wxWidgets + * . + */ + + +// ***************************************************** // +// ***************************************************** // +/*! \page DSP_units_list_page List of DSP units available in DSP Engine + * + * Last update: DSP_lib ver. 0.08.009 <b>2008.03.25</b> file DSP_lib.h + * + * DSP units are listed in several categories: + * - \ref standard_units + * - \ref standard_src_units + * - \ref inout_units + * - \ref multirate_units + * - \ref misc_units + * - \ref specialised_units + * + * \section standard_units Standard processing units (18) + * -# DSP::u::ABS calculates absolute value of real or complex sample + * -# DSP::u::Accumulator implements standard accumulator or accumulator with leakage + * -# DSP::u::Addition addition block (also weighted summation) + * -# DSP::u::Amplifier multiplies input value by given constant + * -# DSP::u::Angle calculates the phase of a complex sample + * -# DSP::u::CCPC CCPC - Cartesian coordinates to polar coordinates converter + * -# DSP::u::CMPO CMPO - complex mutual power operator + * -# DSP::u::Conjugation calculates complex conjugation + * -# DSP::u::CyclicDelay this block is OBSOLETE use DSP::u::Delay instead. + * -# DSP::u::Delay delay element implemented in processing block mode. Inefficient for large buffer (implemented using memcopy). See DSP::u::CyclicDelay. + * -# DSP::u::Differator Differator - first order backward difference operator + * -# DSP::u::FIR FIR filter implementation + * -# DSP::u::IIR IIR filter implementation + * -# DSP::u::LoopDelay delay element implemented in mixed mode (unit-source). Must be used in digital loopbacks. + * -# DSP::u::Multiplication multiplication block + * -# DSP::u::PCCC PCCC - polar coordinated to Cartesian coordinates converter + * -# DSP::u::Power calculates given power of the input signal (real and complex(only integer nonnegative factors)) + * -# DSP::u::RealMultiplication real multiplication block + * . + * + * \section standard_src_units Standard sources (7) + * -# DSP::u::BinRand Generates random binary streams + * -# DSP::u::Const Generates constant signal + * -# DSP::u::COSpulse Generates pulse train + * -# DSP::u::DCO DCO - digitaly controled oscilator + * -# DSP::u::DDScos Generates real/complex cosinusoid on the basis of DDS + * -# DSP::u::Rand Generates uniform noise + * -# DSP::u::LFSR Generates binary sequence with linear feedback shift register + * . + * + * \section inout_units Input/Output units (8) + * -# DSP::u::AudioInput Creates object for recording audio + * -# DSP::u::AudioOutput Creates object for playing audio + * -# DSP::u::FileInput Multichannel file input block - sample format can be specified + * -# DSP::u::FileOutput Multichannel file output block - sample format can be specified + * -# DSP::u::InputBuffer Source block providing input from the memory buffer + * -# DSP::u::OutputBuffer Block providing output to the memory buffer + * -# DSP::u::Vacuum Block for connecting loose outputs + * -# DSP::u::WaveInput Creates object for *.wav files reading + * . + * + * \section multirate_units Multirate units (6) + * -# DSP::u::Demultiplexer Demultiplexer block (y1[n]=x[L*n], y2[n]=x[L*n+1], yL[n]=x[L*n+L-1]) + * -# DSP::u::Multiplexer Multiplexer block (y[L*n]=x1[n], y[L*n+1]=x2[n], y[L*n+L-1]=xL[n]) + * -# DSP::u::RawDecimator Decimator without antialias filter + * -# DSP::u::SampleSelector Outputs some inputs samples on the basis of activation signal + * -# DSP::u::SamplingRateConversion Sampling rate conversion block + * -# DSP::u::Zeroinserter Time expansion block: zeroinserter (+ hold) + * . + * + * \section async_units Asynchronous units (5) + * -# DSP::u::ClockTrigger Clock activation based on input activation signal + * -# DSP::u::GardnerSampling GardnerSampling - sample selection based on Gadner sampling time recovery algorithm + * -# DSP::u::Hold Reads samples from signal activated clocks (asynchronous) and outputs in synchro with standard clock (synchronous) + * -# DSP::u::SampleSelector Outputs samples based on input activation signal, can also activate output clock like DSP::u::ClockTrigger + * -# DSP::u::Farrow Implements Farrow structure based FSD filter. Outputs samples delayed by given fractional delay based + * asynchronously (based on signal activated clock) + * . + * + * \section misc_units Misc units (6) + * -# DSP::u::CrossSwitch CrossSwitch - sends input signals stright or crossed to outputs + * -# DSP::u::Maximum Maximum selector. Outputs: (1) maximum value (2) number of input where maximum is observed + * -# DSP::u::MyFunction User defined function block + * -# DSP::u::Selector Outputs selected input (given by the number) + * -# DSP::u::Splitter Outputs input value to multiple outputs + * -# DSP::u::Switch Gets value from selected input and sends it to the selected output + * . + * + * \section specialised_units Specialised units (6) + * -# DSP::u::AGC AGC - automatic gain control + * -# DSP::u::BPSK_SNR_estimator Signal to noise ratio estimation for BPSK modulation + * -# DSP::u::DynamicCompressor Dynamic compressor/decompressor + * -# DSP::u::PSKdecoder PSK encoder - prepares symbols for PSK modulations + * -# DSP::u::PSKencoder PSK encoder - decodes symbols for PSK modulations + * -# DSP::u::TimingErrorDetector Garder timing error detector + * . + * + * \page DSP_fnc_list_page List of DSP functions available in DSP Engine + * + * Last update: DSP_lib ver. 0.08.009 <b>2008.03.25</b> file DSP_lib.h + * + * \section LOG_fnc LOG related functions + * -# DSP::f::GetLogState() + * -# DSP::f::ErrorMessage() + * -# DSP::f::InfoMessage() + * -# DSP::f::Message() + * -# DSP::f::NoOfErrors() + * -# DSP::f::SetLogFileName() + * -# DSP::f::SetLogFunctionPtr() + * -# DSP::f::SetLogState() + * . + * \section time_fnc Timing functions + * -# DSP::f::SetSleepFunction() + * -# DSP::f::Sleep() + * . + * \section wind_fnc Time windows + * -# DSP::f::Bartlett() + * -# DSP::f::Bartlett_Hann() + * -# DSP::f::Blackman() + * -# DSP::f::Blackman_Harris() + * -# DSP::f::Blackman_Nuttall() + * -# DSP::f::Flat_top() + * -# DSP::f::Gauss() + * -# DSP::f::Hamming() + * -# DSP::f::Hann() + * -# DSP::f::Nuttall() + * -# DSP::f::Rectangular() + * -# DSP::f::Triangular() + * . + * \section misc_DSP_fnc Miscellaneous DSP functions + * -# DSP::f::sinc(DSP::Float) + * -# DSP::f::sinc(int, DSP::Float_ptr) + * . + * \section load_fnc Loading coefficients + * -# DSP_LoadCoef class for loading coeffients from files + * created with MATLAB script >>save_filter_coef.m<< + * located in >>toolbox<< subdirectory. + * Coefficients file can be accessed with functions: + * -# DSP_LoadCoef::Open + * -# DSP_LoadCoef::GetNoOfVectors + * -# DSP_LoadCoef::GetSize + * -# DSP_LoadCoef::Load + * . + * \note Functions listed below are now OBSOLETE + * -# DSP::f::LoadCoeffi1cients_IIR() + * -# DSP::f::LoadCoefficients_CheckSize() + * -# DSP::f::LoadCoefficients_CheckType() + * -# DSP::f::LoadCoefficients_FIR() + * -# DSP::f::LoadCoefficients_IIR() + * . + * -# DSP::f::ReadCoefficientsFromFile() + * . + * \section math_fnc Math functions + * -# DSP::f::gcd() + * -# DSP::f::SolveMatrixEqu() + * -# DSP::f::SolveMatrixEqu_prec() + * . + * \section file_fnc Files related functions + * -# DSP::f::MakeDir() + * -# DSP::f::GetAudioBufferSize() + * -# DSP::f::GetWAVEfileParams() + * -# DSP::f::SaveVector() + * . + * \section mod_fnc Modulations related functions + * -# DSP::f::BER4BPSK() + * -# DSP::f::SER4QPSK() + * -# DSP::f::PSK_SNR_estimator() + * -# DSP::f::PSK_SNR_estimator2() + * . + * + */ +#endif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_logstream.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_logstream.h new file mode 100644 index 0000000000000000000000000000000000000000..bccd75ed1997f7ecc9df7dec09623caf3a42a816 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_logstream.h @@ -0,0 +1,152 @@ +/*! \file DSP_logstream.h + * logging and console output support header file + * + * \author Marek Blok + */ + +#ifndef DSP_TEESTREAM_H +#define DSP_TEESTREAM_H + + #include <ostream> + #include <memory> + #include <mutex> + + #include <DSP_types.h> + + namespace DSP + { + //! Pointer to the Message callback function + /*! bool func(const string &source, const string &message, const bool IsError) + * used in DSP::logstream::Message, DSP::logstream::ErrorMessage, DSP::logstream::InfoMessage + * + * If function returns true all other message logging + * actions will be abandoned. Message will be treated + * as local addressed only for callback function. + */ + typedef bool (*Message_callback_ptr)(const string &, const string &, const bool); + + class logstream; + + namespace e { + enum struct LogMode { + first, // Main part of message (default) + second, // Second part of message + pause, // Force pause after message in Info mode + pause_off, // Dissable pause after message in Error mode + Info, // InfoMessage mode (default) + Error // ErrorMessage mode + }; + + //! LOG actions state enumerations + /*! Several options may be used together + */ + enum struct LogState : unsigned int + { + off=0, + console = 1, + file = console << 1, + append = file << 1, //! only valid with LS_file + errors_only = append << 1, + user_function = errors_only << 1, + + file_append= (file | append) + }; + inline LogState operator|(LogState __a, LogState __b) + { return LogState(static_cast<unsigned int>(__a) | static_cast<unsigned int>(__b)); } + inline LogState operator&(LogState __a, LogState __b) + { return LogState(static_cast<unsigned int>(__a) & static_cast<unsigned int>(__b)); } + } + + + class logbuf; + + typedef std::shared_ptr<logbuf> logbuf_ptr; + } + + DSP::logstream& operator<< (DSP::logstream& os, const DSP::e::LogMode& log_mode); + + namespace DSP { + + class logstream : public std::ostream // std::basic_ostream + { + public: + // Construct an ostream which forwards output to DSP::InfoMessage and DSP::ErrorMessage. + logstream(void); + ~logstream(void); + + friend logstream& ::operator<< (logstream& os, const DSP::e::LogMode& log_mode); + + public: + //! Sets current LOG actions state + void SetLogState(const DSP::e::LogState &Mode); + //! Returns current LOG actions state + DSP::e::LogState GetLogState(void); + //! Sets/changes current LOG file name + /*! + * \warning this function does not change LOG state to LS_file + * it must be done manually with SetLogState + * + * \warning File is created when first LOG message is issued + * with ErrorMessage, InfoMessage or Message. + * !!! WriteMessage2File function must be used + * + * If file is not opened, the stored file_name is simply changed. + * + * If LOG file is open, it is closed and file_name is changed. + * New file will be created when next LOG message will be issued. + */ + void SetLogFileName(const string &file_name); + //! Sets/changes current user LOG Message processing function + void SetLogFunctionPtr(Message_callback_ptr function_ptr); + + //! Returns number of Errors registered by ErrorMessage function for given DSP::logstream object + /*! If Reset is true function zeros the counter + */ + long int NoOfErrors(bool Reset=true); + + private: + void init_logstream(); + + logbuf_ptr log_buf; + }; + + //! "globalny" log stream + extern logstream log; + + #ifndef __DEBUG__ + // Wyłączenie komunikatów mtee_dbg jeżeli nie zdefiniowano flagi __DEBUG__ + + // zapewnia poprawność skÅ‚adni ale jednoczeÅ›nie deaktywuje przetwarzanie wszystkich strumieni dla mtee_dbg + #define log_dbg \ + if (false) log + + #else + // użycie w trybie __DEBUG__ + + #define log_dbg log //! output stream active only in debug mode + + #endif // __DEBUG__ + + + +} + +// template <class charT, class Traits> +// inline basic_ostream<charT,Traits>& operator<< (basic_ostream<charT,Traits>& os, const DSP::e::LogMode& log_mode) { +inline ostream& operator<< (ostream& os, const DSP::e::LogMode& log_mode) { + DSP::logstream *p; + try { + p = dynamic_cast<DSP::logstream*>(&os); + } + catch (const std::bad_cast &) + { + return os; + } + + *p << log_mode; + return os; +} + + + +#endif // DSP_TEESTREAM_H diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_misc.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_misc.h new file mode 100644 index 0000000000000000000000000000000000000000..6a88f169d96ea49eb191428031bd55ce084d1a1b --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_misc.h @@ -0,0 +1,410 @@ +//--------------------------------------------------------------------------- +/*! \file DSP_misc.h + * This is DSP engine auxiliary functions module header file. + * + * \author Marek Blok + */ +/*! + * \defgroup misc_func Miscellaneous functions + * + * \defgroup ver_data Version and major changes information + * + * + * \addtogroup misc_func + * @{ + */ +#ifndef DSP_misc_H +#define DSP_misc_H + +#ifdef __GNUC__ + #include <sys/stat.h> + #include <sys/types.h> + #include <dirent.h> +#elif defined(__BORLANDC__) + #include <direct.h> +#elif defined(_MSC_VER) + #pragma message ("test _MSC_VER") + //#define _WINSOCK_DEPRECATED_NO_WARNINGS + //#define _CRT_SECURE_NO_WARNINGS + #pragma warning (disable : 4250 ) // do zweryfikowania: dziedziczenie jednej metody z dw�ch klas bazowych + + #if defined(_AMD64_) + #pragma message ("_AMD64_") + #elif defined(_X86_) + #pragma message ("_X86_") + #endif + #if defined(_WIN32) + #pragma message ("_WIN32") + #endif + +#else + #error Compiler not supported +#endif + +#include <fstream> +#include <string> + +using namespace std; + +//--------------------------------------------------------------------------- +#include <DSP_setup.h> +#include <DSP_logstream.h> +//--------------------------------------------------------------------------- +#include <DSP_types.h> +// All function names should begin with DSP::f:: + +namespace DSP { + namespace e { + enum struct LoadCoef_Type : unsigned int; // DSPe_LoadCoef_Type + LoadCoef_Type operator|(LoadCoef_Type __a, LoadCoef_Type __b); + } + class LoadCoef; + + namespace f { + //! Greatest Common Dividor + unsigned long gcd(unsigned long a, unsigned long b); + + //! Solves matrix equation using Gaussian elimination with backsubstitution + void SolveMatrixEqu(const vector<DSP::Float_vector> &A_in, //! square matrix of coefficients (table of rows) + DSP::Float_vector &X, //!vector reserved for solution + const DSP::Float_vector &B_in); //!right-hand side quantities vector + + //! Solves matrix equation using Gaussian elimination with backsubstitution + /*! All calculations are internally done at high precision + */ + void SolveMatrixEqu_prec( + const vector<DSP::Float_vector> &A_in, //!matrix coefficients (table of rows) + DSP::Float_vector &X_in, //!vector reserved for solution + const DSP::Float_vector &B_in); //!right-hand side quantities vector + //! Solves matrix equation using Gaussian elimination with backward substitution + /*! All calculations are internally done at high precision based on high precision input coefficients + * \note suggested use_pivoting = 2 + * \note use_pivoting = 0 should not be used + */ + void SolveMatrixEqu_prec( + const vector<DSP::Prec_Float_vector> &A_in, //!matrix coefficients (table of rows) + DSP::Prec_Float_vector &X_in, //!vector reserved for solution + const DSP::Prec_Float_vector &B_in, //!right-hand side quantities vector + int use_pivoting); //! pivoting mode: 0-none; 1-rows; 2-rows&cols + + //! Minimax filter design based on real Remez exchange algorithm + /*! - N - filter impulse response length (order N-1) + * - h_buffer - buffer for impulse response + * also needed: filter prototype in frequency domain, + * weighting function, approximation bandwidths, ... + */ + void RealRemez(int N, DSP::Float_vector &h_buffer); + + //! Least-squares lowpass filter design + /*! + * - N - filter impulse responce length (order N-1) + * - fp - passband upper frequency + * - fs - stopband lower frequency + * - Ws - stopband error weighting coefficient (Wp = 1) + * - h_buffer - user buffer for impulse response + * . + */ + void LPF_LS (int N, DSP::Float fp, DSP::Float fs, DSP::Float_vector &h_buffer, DSP::Float Ws = 1.0); + + //! Creates subdirectory in parent_dir + /*! \warning if parent_dir != NULL then it must exist. + * \warning Will create single subdirectory (no nested subdir creation) + */ + bool MakeDir(const string &dir_name, const string &parent_dir = ""); + //! Splits directory name into bits and tries to create it subdirectory by subdirectory + void MakeDir_Ex(const string &dir_name); + + + //! Symbol error rate estimation for QPSK + DSP::Float SER4QPSK(DSP::Float SNR_lin); + //! Bit error rate estimation for QPSK + DSP::Float BER4BPSK(DSP::Float SNR_lin); + + //! implemented in DSP_IO.cpp + void Sleep(uint32_t time); + //! implemented in DSP_IO.cpp + void SetSleepFunction(DSP::ExternalSleep_ptr new_function); + + //! Divides each window sample by sum of all samples. + /*! Gives window with frequency response equal 1 at 0 frequency. + */ + void normalise_window(int size, DSP::Float_ptr buffer); + + //! Blackman window + /*! \f$w[n] = 0.42 - 0.5\cos\left(\frac{2{\pi}n}{N-1}\right) + + 0.08\cos\left(\frac{4{\pi}n}{N-1}\right)\f$ + */ + void Blackman(int size, DSP::Float_ptr buffer, bool normalize = false); + + //! Hamming window + /*! \f$w[n] = 0.53836 - 0.46164\cos\left(\frac{2{\pi}n}{N-1}\right)\f$ + */ + void Hamming(int size, DSP::Float_ptr buffer, bool normalize = false); + + //! von Hann window + /*! \f$w[n] = 0.5 - 0.5\cos\left(\frac{2{\pi}n}{N-1}\right)\f$ + */ + void Hann(int size, DSP::Float_ptr buffer, bool normalize = false); + + //! Bartlett window (zero valued end-points) + /*! \f$w[n] = \frac{2}{N-1} \left( + * \frac{N-1}{2} - \left| n - \frac{N-1}{2} \right| + * \right) \f$ + */ + void Bartlett(int size, DSP::Float_ptr buffer, bool normalize = false); + + //! Triangular window (non-zero end-points) + /*! \f$w[n] = \frac{2}{N} \left( + * \frac{N}{2} - \left| n - \frac{N-1}{2} \right| + * \right) \f$ + */ + void Triangular(int size, DSP::Float_ptr buffer, bool normalize = false); + + //! Bartlett-Hann window + /*! \f$w[n] = 0.62 + * - 0.48 \left| \frac{n}{N-1} - \frac{1}{2} \right| + * - 0.38 \cos\left(\frac{2{\pi}n}{N-1}\right)\f$ + */ + void Bartlett_Hann(int size, DSP::Float_ptr buffer, bool normalize = false); + + //! Gauss window + /*! \f$w[n] = \exp ^ { + * - \frac{1}{2} + * \left( + * \frac + * {n - (N-1)/2} + * {\sigma(N-1)/2} + * \right) ^ 2 + * }\f$ + * where \f$\sigma <= 0.5\f$ + */ + void Gauss(int size, DSP::Float_ptr buffer, DSP::Float sigma, bool normalize = false); + + //! Rectangular window + /*! \f$w[n] = 1\f$ + */ + void Rectangular(int size, DSP::Float_ptr buffer, bool normalize = false); + + //! Nuttall window, continuous first derivative + /*! \f$w[n] = 0.355768 + * - 0.487396 \cos\left(\frac{2{\pi}n}{N-1}\right) + * + 0.144232 \cos\left(\frac{4{\pi}n}{N-1}\right) + * - 0.012604 \cos\left(\frac{6{\pi}n}{N-1}\right) + * \f$ + */ + void Nuttall(int size, DSP::Float_ptr buffer, bool normalize = false); + + //! Blackman-Harris window, continuous first derivative + /*! \f$w[n] = 0.35875 + * - 0.48829 \cos\left(\frac{2{\pi}n}{N-1}\right) + * + 0.14128 \cos\left(\frac{4{\pi}n}{N-1}\right) + * - 0.01168 \cos\left(\frac{6{\pi}n}{N-1}\right) + * \f$ + */ + void Blackman_Harris(int size, DSP::Float_ptr buffer, bool normalize = false); + + //!Blackman-Nuttall window + /*! \f$w[n] = 0.3635819 + * - 0.4891775 \cos\left(\frac{2{\pi}n}{N-1}\right) + * + 0.1365995 \cos\left(\frac{4{\pi}n}{N-1}\right) + * - 0.0106411 \cos\left(\frac{6{\pi}n}{N-1}\right) + * \f$ + */ + void Blackman_Nuttall(int size, DSP::Float_ptr buffer, bool normalize = false); + + //!Flat top window + /*! \f$w[n] = 1 + * - 1.93 \cos\left(\frac{2{\pi}n}{N-1}\right) + * + 1.29 \cos\left(\frac{4{\pi}n}{N-1}\right) + * - 0.388 \cos\left(\frac{6{\pi}n}{N-1}\right) + * + 0.032 \cos\left(\frac{8{\pi}n}{N-1}\right) + * \f$ + */ + void Flat_top(int size, DSP::Float_ptr buffer, bool normalize = false); + + //! Normalized sinc function + /*! - Input: buffer contains funtion argumets + * - Output: results are stored in buffer (input values will be overwritten) + * + * \f$x(x) = \frac{\sin({\pi}x)}{{\pi}x)}\f$ + */ + void sinc(int size, DSP::Float_ptr buffer); + //! Normalized sinc function + /*! - Input: arguments contains funtion argumets + * - Output: returns results + * + * \f$x(x) = \frac{\sin({\pi}x)}{{\pi}x)}\f$ + */ + template <typename T> + void sinc(const DSP::Float_vector& arguments, vector<T> &output_buffer); + + //! Normalized sinc function + /*! + * \f$x(x) = \frac{\sin({\pi}x)}{{\pi}x)}\f$ + */ + DSP::Float sinc(DSP::Float x); + DSP::Prec_Float sinc_prec(DSP::Prec_Float x); + + //! Saves to *.flt file samples from given real valued vector with information out its sampling rate + bool SaveVector(const std::string &filename, const DSP::Float_vector &vector, const unsigned int &Fp=0); + //! Saves to *.flt file samples from given complex valued vector with information out its sampling rate + bool SaveVector(const std::string &filename, const DSP::Complex_vector &vector, const unsigned int &Fp=0); + + + //! returns sample size in bytes for given sample type + int SampleType2SampleSize(DSP::e::SampleType type); + } +} + +// ***************************************************** // +// ***************************************************** // +// ***************************************************** // + + +/*! \addtogroup load_func Config/data files processing functions + * @{ + */ +//! LoadCoeffient file type enumerations +/*! Several options may be used together + */ +enum struct DSP::e::LoadCoef_Type : unsigned int // DSPe_LoadCoef_Type +{ + error = 0, // DSP_LC_error + + real = 1, // DSP_LC_real + complex = real << 1, // DSP_LC_complex + + FIR = complex << 1, // DSP_LC_FIR + IIR = FIR << 1, // DSP_LC_IIR + + FIR_real = (FIR | real), // DSP_LC_FIR_real + FIR_complex = (FIR | complex), // DSP_LC_FIR_complex + IIR_real = (IIR | real), // DSP_LC_IIR_real + IIR_complex = (IIR | complex) // DSP_LC_IIR_complex + +}; +// DSP::e::LoadCoef_Type operator|(DSP::e::LoadCoef_Type __a, DSP::e::LoadCoef_Type __b) +// { +// return DSP::e::LoadCoef_Type(static_cast<int>(__a) | static_cast<int>(__b)); +// } +inline DSP::e::LoadCoef_Type DSP::e::operator|(DSP::e::LoadCoef_Type __a, DSP::e::LoadCoef_Type __b) +{ + return static_cast<DSP::e::LoadCoef_Type>(static_cast<std::underlying_type<DSP::e::LoadCoef_Type>::type>(__a) + | static_cast<std::underlying_type<DSP::e::LoadCoef_Type>::type>(__b)); +} + + +//! LoadCoeffient file info structure +/*! Stores information retrieved from coefficients file + */ +class DSP::LoadCoef +{ + public: + string filename; // file name with path + + unsigned char file_version; + + DSP::e::LoadCoef_Type type; // DSPe_LoadCoef_Type + + DSP::e::SampleType sample_type; + int sample_size; //! sample component size in bytes + unsigned char sample_dim; //! sample dimension: 1 - real, 2 - complex, ... + + int NoOfVectors; //! -1 if unsupported format + unsigned int Fp; //! sampling frequency (valid if file_version > 0) + + int header_size; //! number of bytes in header + + //! constructor + LoadCoef(void) + { + file_version = 0xff; + filename[0] = 0x00; + + header_size = 0; + sample_dim = 0; + + type = DSP::e::LoadCoef_Type::error; + sample_type = DSP::e::SampleType::ST_none; + sample_size = -1; + NoOfVectors = -1; + Fp = 0; + } + + //! Opens Coefficients file & fills structure + /*! File format (*.coef) - this is open format, for general use + * (not only for storing coefficients) + * + * - (uchar) 1B - file version number + * - data - coefficients data (depends on file version) + * . + * Data segment format: + * -# (version: >= 0x01) + * - (uint) 4B - sampling frequency + * -# (version: >= 0x00) + * - (uchar) 1B - number of sample dimensions + * 1 - real, 2 - complex, ... + * - (uchar) 1B - sample component type + * - DSP::e::FileType::FT_float (=1) : C++ float (32bit floating point) + * - DSP::e::FileType::FT_short (=2) : C++ short (16bit signed integer) + * - DSP::e::FileType::FT_uchar (=3) : C++ unsigned char (8bit unsigned integer with bias (0x80)) + * - DSP::e::FileType::FT_double (=7) : C++ double (64bit floating point) + * - DSP::e::FileType::FT_long_double (=8) : C++ long double (80bit floating point) + * - (uchar) 1B - number of vectors + * - 1 - FIR filter coefficients (one vector) + * - 2 - IIR filter coefficients (two vectors) + * - (x number of vectors) + * - (ushort) 2B - number of samples in vector + * - (x number of samples) + * - (x number of sample dimensions) + * - (sample component type) xB - sample component + * e.g. real, imag part + * + * @return Returns false on error. + */ + bool Open(const string &Filename, const string &Dir); + + //! Checks Coefficients size for given vector + /*! \param vector_no = 0, 1, ... + * - 0 - numerator coefficients (FIR or IIR filters) + * - 1 - denominator coefficients (only IIR filters) + * . + * Larger values can be used for files with + * multiple responses sets. + * + * @return Returns size on success and -1 on error. + */ + int GetSize(int vector_no = 0); + //! Returns number of vectors in file + int GetNoOfVectors(void); + + //! Loads complex coefficients vector + /*! + * \param FIR_coef - pointer to vector where coefficients will be stored + * \param vector_index - index of coefficients vector to read. + * Typically 0, but can be used to read from file + * containing set of FIR filter responses. All the responses + * must be complex. + * + * Returns FALSE if file type or size mismatch is detected. + */ + bool Load(DSP::Complex_vector &FIR_coef, int vector_index = 0); + //! Loads real coefficients vector + /*! + * \param FIR_coef - pointer to vector where coefficients will be stored + * \param vector_index - index of coefficients vector to read. + * Typically 0, but can be used to read from file + * containing set of FIR filter responses. All the responses + * must be complex. + * + * Returns FALSE if file type mismatch is detected. + */ + bool Load(DSP::Float_vector &FIR_coef, int vector_index = 0); +}; + +/*@} load_func*/ + +/*@} misc_func*/ + +#endif + diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_modules.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_modules.h new file mode 100644 index 0000000000000000000000000000000000000000..9f5d9d5aa3de62970967c1f5087209969b3a0758 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_modules.h @@ -0,0 +1,3903 @@ +/*! \file DSP_modules.h + * This is DSP engine components and sources definition module header file. + * + * \author Marek Blok + */ +#ifndef DSPmodulesH +#define DSPmodulesH + +//#include <string.h> +//#include <cmath> +//#include <stdio.h> +#include <iostream> +#include <fstream> +#include <map> +#include <vector> + +#include <string> +#include <sstream> + +//--------------------------------------------------------------------------- +#include <DSP_setup.h> +//--------------------------------------------------------------------------- +#include <DSP_types.h> +#include <DSP_misc.h> + +using namespace std; + +//#include <DSPclocks.h> + +namespace DSP { + class Clock_trigger; + class clocks_relation; + class clock_groups; + class input; + class output; + + class name; + + class _connect_class; //private connect functions + + class Randomization; +} + +namespace DSP { + class Component; + class Block; + class Source; + + class MacroStack; +} + +namespace DSP { + namespace u { + class Copy; + class Delay; + class LoopDelay; + class Splitter; + class Amplifier; + class Addition; + class Power; + class Multiplication; + class RealMultiplication; + class RawDecimator; + class Zeroinserter; + class Const; + class Rand; + class BinRand; + class LFSR; + class LFSR_tester; + class COSpulse; + class DDScos; + class DCO; + class IIR; + class FIR; + class Differator; + class Accumulator; + class SamplingRateConversion; + class Maximum; + class Selector; + class SampleSelector; + class ClockTrigger; + class CrossSwitch; + class Conjugation; + class ABS; + class Angle; + class CMPO; + class PCCC; + class CCPC; + class MyFunction; + class Hold; + class Demultiplexer; + class Multiplexer; + class Quantizer; + } +} +bool operator>>( const DSP::output &output, const DSP::input &input); +bool operator<<( const DSP::input &input, const DSP::output &output); + +class DSP::_connect_class { + friend bool ::operator>>( const DSP::output &output, const DSP::input &input); + friend bool ::operator<<( const DSP::input &input, const DSP::output &output); + + protected: + static bool connect(const output &output, const input &input, bool AllowSplit = true); + static bool splitconnect(const output &output, const input &input); +}; + +//! Object containing informations about specific output of a block +/*! That allows for outputs can be composed of several output lines + */ +class DSP::output +{ + private: + bool _is_null = false; + + //! null output object + static DSP::output _null; + + //! output name + string _name; + public: + + //! connects the given output to the given input + /*! returns true if succeeds + * Makes use of DSP::Block::SetOutput function + */ + friend bool ::operator>>( const DSP::output &output, const DSP::input &input ); + + //! read output name + const string &get_name(void) const; + //! set output name + void set_name(const string &name); + + //! pointer to the component with the given output + DSP::Component_ptr component; + //! indexes of output lines + vector <unsigned int> Outputs; + + //! returns null output object + inline static DSP::output &null(){ + return _null; + } + + inline bool is_null() const{ + return _is_null; + } + + output(const bool &create_null = false); + ~output(void); +}; + +//! Object containing informations about specific input of a block +/*! This allows for outputs that can be composed of several input lines. + */ +class DSP::input +{ + private: + bool _is_null = false; + + //! null input object + static DSP::input _null; + + //! input name + string _name; + + public: + //! connects the given output to the given input + /*! returns true if succeeds + * Makes use of DSP::Block::SetOutput function + */ + friend bool ::operator<<( const DSP::input &input, const DSP::output &output); + + //! read input name + const string &get_name(void) const; + //! set input name + void set_name(const string &name); + + //! pointer to the component with the given output + DSP::Component_ptr component; + //! indexes of input lines + vector <unsigned int> Inputs; + + //! returns null input object + inline static DSP::input &null(){ + return _null; + } + + inline bool is_null() const { + return _is_null; + } + + input(const bool &create_null = false); + ~input(void); +}; + +//! Object containing information about name of specific object +/*! Fixed <b>2005.10.30</b> This class is empty in release mode. + * And in such a case returns NULL as name. + * + * \warning debug libraries must be created with -I../src/include/dbg + * \warning release libraries should be created with -I../src/include/rls + */ +class DSP::name +{ + private: + #if __DEBUG__ == 1 + //! Name of the object + string ObjectName; + #endif + public: + name(void); + name(const string &Name); + + //! Sets the name of the block + void SetName(const string &Name, bool Append=true); + //! Returns the block's name + string GetName(); +}; + +// ***************************************************** // +// ***************************************************** // +/*! \page DSP::Block_page DSP::Block and DSP::Source descendant components creation rules + * + * All DSP units implemented in this engine are based on two classes: + * DSP::Source and DSP::Block. Both these classes are based on DSP::Component class. + * The first class (DSP::Source) has only outputs and its execution is + * controlled by one of user defined clocks (DSP::Clock). The second class + * (DSP::Block) has both inputs and outputs. The execution of DSP::Block object + * takes place when the input value is fed into the object. Strictly speaking + * block processing finishes after the last input value has been received + * in the current clock cycle. + * + * \note + * <b>1.</b> Names of all DSP units classes should start from <b>DSP::u::</b> (e.g. DSP::u::ABS), + * where 'u' stands for unit. + * \note + * <b>2.</b> Names of enumeration types should begin with <b>DSP::e::</b>. + * \note + * <b>3.</b> Names of auxiliary functions should begin with <b>DSP::f::</b>. + * \note + * <b>4.</b> Names of auxiliary objects should begin with <b>DSP::o::</b>. + * + * + * Three types of DSP units can be implemented: + * -# Processing unit: processes input values and sends resulting value + * to the output (class based on DSP::Block). See: \ref devel_processing_block_ex. + * -# Source unit: generates (that also mean reading values from external + * sources like sound cards or files) value and sends it to the output + * (class based on DSP::Source). See: \ref devel_source_block_ex. + * -# Mixed blocks: units which process input samples like + * processing units but change sampling frequency or the output value + * might be needed before the input is ready. (class based on DSP::Block and DSP::Source). + * We can distinguish two types of such units: + * - resampling components: the input works with different clock + * than the output + * - asynchronous components: input and output work with independent clocks; + * at least one of them is the signal activated clock. See \ref alg_cr_clocks. + * - digital feedback loop separation components: output value might + * be needed before the input is received. To this category belong mainly + * delay units that are necessary to implement digital feedback loops. + * . + * + * + * \section main_recom_ Main recommendations + * The new DSP unit must be descendant class of DSP::Source or DSP::Block or both. + * In this class at least following elements must be implemented + * - \ref constr_ "constructor" and \ref destr_ "destructor" + * - in processing unit: static function <b>bool Execute(int InputNo, DSP::Float value);</b>. + * \ref proc_exec_ "See ..." + * - in source unit: static function <b>bool Execute(void);</b> + * \ref source_exec_ "See ..." + * - in mixed block both \b Execute static functions must be implemented + * \ref mixed_exec_ "See ..." + * + * + * + * \section const_inputs_ Constant inputs support + * This engine has implemented basic support for constant inputs. + * The main support is provided by function DSP::Block::SetNoOfInputs. + * This function sets + * - IsConstantInput[InputNo] + * - ConstantInputValues[InputNo] + * - InitialNoOfInputsProcessed (equals number of constant inputs) + * . + * If block supports use of the constant inputs it must: + * - In block constructor use DSP::Block::SetNoOfInputs with AllowForConstantInputs == <b>true</b> + * Such a block is initialized to support constant inputs and + * DSP::Block::IsUsingConstants variable is set to true. + * - Block input execution function <b>MUST</b> init DSP::Block::NoOfInputsProcessed variable + * with DSP::Block::InitialNoOfInputsProcessed. + * - In algorithm creation function use DSP::Block::SetConstInput + * to set values to inputs you want to have constant value. + * \warning At least one input must be left non-constant. + * If all input should be constant use DSP::u::Constant source + * block for at least one input. + * - If block requires additional processing when constant input is set, + * implement descendant function for void DSP::Block::RecalculateInitials (void). + * This function is called each time when DSP::Block::SetConstInput is called. + * Make use of DSP::Block::IsConstantInput and DSP::Block::ConstantInputValues. + * . + * + * \code + void DSP::u::MyBlock_with_constant_inputs::RecalculateInitials (void) + { + int ind; + + for (ind=0; ind<NoOfInputs; ind++) + { + if (IsConstantInput[ind] == true) + { + State[ind] = ConstantInputValues[ind]; + } + } + } + \endcode + * + * + * \section constr_ Constructor + * In constructor there should be: + * -# In both processing block and source + * - \ref DSP::Block::SetNoOfOutputs "SetNoOfOutputs(Number)" <- declaration that block has + * Number outputs. Apart from other initialisation actions this will set DSP::Block::NoOfOutputs variable. + * \note two outputs must be declared per one complex valued output. + * - \ref #DSP::Block::SetNoOfInputs "SetNoOfInputs(Number)" <- declaration that block has + * Number inputs. Apart from other initialisation actions this will set DSP::Block::NoOfInputs variable. + * \note two inputs must be declared per one complex valued input. + * . + * -# Only in source or mixed block + * - \link #DSP::Block::IsMultiClock IsMultiClock\endlink = \b false; <- When all outputs are controled + * by the same clock + * - \link #DSP::Block::IsMultiClock IsMultiClock\endlink = \b true; <- When some outputs are controled + * by different clocks (this option is not fully functional yet) + * - \link #DSP::Block::OutputClocks OutputClocks\endlink must be filled + * and the source must be \ref DSP::Source::RegisterOutputClock + * "registered" for this clock. For further details + * see \ref source_regist "Registering Source". + * If necessary also source notifications should be set here + * with DSP::Component::RegisterForNotifications. + * . + * -# Inputs and outputs names definitions + * - DSP::Block::DefineInput + * - DSP::Component::DefineOutput + * . + * . + * + * + * \section destr_ Destructor + * Destructor is optional because following are executed + * in \link DSP::Block::~DSP::Block parent destructor\endlink + * instead of descendant block destructor or after descendant + * block destructor is processed: + * - In mixed or source components: \link DSP::Source::UnregisterOutputClocks UnregisterOutputClocks\endlink (); + * - \link DSP::Block::SetNoOfOutputs SetNoOfOutputs\endlink (0); + * + * It is only neccessary to free all resources allocated in + * descendant block constructor + * + * + * \section source_regist Registering Source + * Each source must register in the clock which sychronises + * its output(s) processing. To do this + * -# Proper clock must be obtained using DSP+clock::CreateMasterClock or + * DSP::Clock::GetClock function. Parent clock is usally passed as the + * parameter to the source block contructor. + * -# Pointer to this clock must be stored in \link #DSP::Block::OutputClocks + * OutputClocks\endlink. \n + * If DSP::Source::IsMultiClock == <b>false</b>, it is + * enough to set OutputClocks[0]. Otherwise OutputClocks table must be set + * for each output. + * -# The source must be register to the output clock using + * \link DSP::Source::RegisterOutputClock RegisterOutputClock \endlink function. + * -# DSP::Component::RegisterForNotification - register clock for source + * notifications and begining of the reference clock cycle. See also \ref asynch_block. + * + * Example 1: (standard source or mixed blocks retaining + * sampling frequency) + * \code + if (ParentClock != NULL) + OutputClocks[0]=ParentClock; + else + OutputClocks[0]=DSP::Clock::GetClock(); + RegisterOutputClock(OutputClocks[0]); + \endcode + * + * Example 2: (mixed blocks with sampling frequency change) + * \code + OutputClocks[0]=DSP::Clock::GetClock(ParentClock, L, M); + RegisterOutputClock(OutputClocks[0]); + \endcode + * + * + * \section proc_exec_ Processing block execution function + * + * In processing block static member function of the type ::DSP::Block_Execute_ptr + * for block's input values handling must be implemented. + * Pointer to this function must be set to DSP::Block::Execute_ptr variable. + * \code + * class DSP_test : public DSP::Block + * { + * private: + * // ... + * static void Execute_test(DSP::Block_ptr block, int InputNo, DSP::Float value, DSP::Component *Caller); + * public: + * // ... + * DSP_test(...); + * + * }; + * + * void DSP_test::Execute_test(DSP::Block_ptr block, int InputNo, DSP::Float value, DSP::Component *Caller) + * { + * / * ... * / + * } + * + * DSP_test::DSP_test(...) : DSP::Block() + * { + * / * ... * / + * Execute_ptr = &Execute_test; + * } + * \endcode + * + * This function is executed when input sample for input number + * InputNo is ready and its value is given. + * When all needed input values (if there are more inputs) + * are ready, the function should calculate output sample + * end send the output values to next blocks. + * + * + * Example 1: + * \code + #define THIS_ ((DSP_test *)block) + void DSP_test::Execute(DSP::Block_ptr block, int InputNo, DSP::Float value) + { + THIS_->OutputBlocks[0]->Execute_1(THIS_->OutputBlocks_InputNo[0], 0.5*value); + } + #undef THIS_ + \endcode + * + * In above example input value is multiplied by 0.5 and + * send to first output. Output number OutputBlocks_InputNo[0] + * of block OutputBlocks[0]. + * + * + * Example 2: + * \code + #define THIS_ ((DSP_test *)block) + void DSP_test::Execute_2(int InputNo, DSP::Float value) + { + int ind; + + for (ind=0; ind<THIS_->NoOfOutputs; ind++) + THIS_->OutputBlocks[ind]->Execute(THIS_->OutputBlocks_InputNo[ind], value); + } + #undef THIS_ + \endcode + * + * In example 2 input value is redistributed to several outputs. + * + * + * Example 3: + * \code + #define THIS_ ((DSP_test *)block) + void DSP_test::Execute_3(int InputNo, DSP::Float value) + { + //In general we should check whether each input is executed only once per cycle + THIS_->State += value; + THIS_->NoOfInputsProcessed++; + + if (THIS_->NoOfInputsProcessed == THIS_->NoOfInputs) + { + THIS_->OutputBlocks[0]->Execute(THIS_->OutputBlocks_InputNo[0], THIS_->State); + THIS_->State=0.0; + THIS_->NoOfInputsProcessed=THIS_->InitialNoOfInputsProcessed; + } + }; + #undef THIS_ + \endcode + * + * In example 3 values from several inputs are added up + * and then sent to the output block. + * Two additional variables declared in block are used: + * \code + DSP::Float State; + unsigned int NoOfInputsProcessed; + \endcode + * + * \b State stores temporary output result and \b NoOfInputsProcessed + * stores number of input values already received. + * + * \note Each block can have more then one Execute function. + * That way input processing function can be selected + * depending on input parameters of block constructor + * or later e.g. when some of inputs are set to be constant + * or some block parameters are changed. + * + * + * + * \section source_exec_ Source execution function + * + * In source static member function of a type ::DSP::Source_Execute_ptr + * for output values generation handling must be implemented. + * Pointer to this function must be set to DSP::Source::OutputExecute_ptr. + * + * \code + * class DSP_test : public DSP::Source + * { + * private: + * // ... + * static bool OutputExecute_test(DSP::Source_ptr source, DSP::Clock_ptr clock); + * public: + * // ... + * DSP_test(...); + * + * }; + * + * bool DSP_test::OutputExecute_test(DSP::Source_ptr source, DSP::Clock_ptr clock) + * { + * / * ... * / + * } + * + * DSP_test::DSP_test(...) : DSP::Source(ParentClock) + * { + * / * ... * / + * OutputExecute_ptr = &OutputExecute_test; + * } + * \endcode + * must be implemented. This function is executed when + * the clock in which the source output is registered + * is activated. The clock variable stores the pointer to + * the clock which executed this function. This variable can + * be used to distinguish different clocks in sources with mutiple + * outputs working with different clocks. + * + * This function should return false when source is not ready yet, + * and true when source was ready and sent the output value(s). + * + * Example: + * \code + #define THIS_ ((DSP_test *)source) + bool DSP_test::OutputExecute_1(DSP::Source_ptr source, DSP::Clock_ptr clock) + { + THIS_->OutputBlocks[0]->Execute(THIS_->OutputBlocks_InputNo[0], 1.0); + return true; + } + #undef THIS_ + \endcode + * + * In this example source simply sends 1.0 to first output + * and returns true. In this case source doesn't need + * to wait for external resources and is always ready. + * + * \note Just like in case of processing blocks each source + * can have more then one Execute function. + * That way output processing function can be selected + * depending on input parameters of source constructor + * or later e.g. when some of source parameters are changed. + * + * See also DSP::Component::Notify() which can be overloaded if notification + * at begining of each input clock cycle is required (e.g. in + * \ref asynch_block "asynchrounous blocks"). However, source must be + * also registered for notifiations with DSP::Component::RegisterForNotification. + * + * + * \section mixed_exec_ Mixed block execution functions + * + * Mixed blocks must have implemented both execution functions. + * First, static member input processing function + * of the type ::DSP::Block_Execute_ptr (see \ref proc_exec_) + * which is neccessary to receive and manage storing input samples. + * Second, static member output generation function + * of the type ::DSP::Source_Execute_ptr (see \ref source_exec_) + * which is used to provide output samples. + * + * \warning This two functions must be designed very carrefully. + * When the block will serve as + * \ref alg_cr_feedback "digital feedback loop separation component" + * , it is crucial that the results are the same no mather which function is executed first. + * + * \note In case of <b>resampling components</b> we don't need + * to be so strict, and we can force <b>DSP::Source::OutputExecute_ptr</b> + * function to be executed second, by returning <b>false</b>, + * when input values haven't been yet received. This will postpone + * this function execution. That way we can ensure that function + * <b>DSP::Block::InputExecute_ptr</b> is executed first. + * + * The following example demonstrate how to do it with the use of + * DSP::Block::NoOfInputsProcessed variable. However, use might in + * same case might use another variable for indication that + * all required input samples are ready. + * + \code + #define THIS ((DSP::u::DDScos *)block) + void DSP::u::DDScos::InputExecute( DSP::Block * block, + unsigned int InputNo, + DSP::Float value, + DSP::Component * Caller ) + { + THIS->NoOfInputsProcessed++; + switch (InputNo) + { + case 0: //amplitude + THIS->A=value; + break; + case 1: //angular frequency + THIS->frequency=value/DSP::M_PIx2; + break; + case 2: //initial phase + THIS->phase=value/DSP::M_PIx2; + break; + default: + break; + } + } + + bool DSP::u::DDScos::OutputExecute_real(DSP::Source_ptr source, DSP::Clock_ptr clock) + { + if (THIS->NoOfInputsProcessed < NoOfInputs) + { //Not all parameters are already read + return false; + } + + // This must be reset + THIS->NoOfInputsProcessed = THIS->InitialNoOfInputsProcessed; + + // Generate output sample + THIS->OutputBlocks[0]->Execute_ptr( + THIS->OutputBlocks[0], THIS->OutputBlocks_InputNo[0], + THIS->A * cos(DSP::M_PIx2 * (THIS->CurrentPhase + THIS->phase)), source); + + //Update phase for next sample + THIS->CurrentPhase += THIS->frequency; + if (THIS->CurrentPhase<0) + { + THIS->CurrentPhase -= 0.5; + THIS->CurrentPhase = fmod(THIS->CurrentPhase, 1.0); + THIS->CurrentPhase += 0.5; + } + else + if (THIS->CurrentPhase > 0) + { + THIS->CurrentPhase += 0.5; + THIS->CurrentPhase = fmod(THIS->CurrentPhase, 1.0); + THIS->CurrentPhase -= 0.5; + } + + return true; + } + #undef THIS + \endcode + * + * The overall idea is that InputExecute function + * - collects input samples + * - when all required samples are colleted, mark them as ready to be processed + * . + * In OutputExecute function + * - if InputExecute have not yet collected all necessary samples, + * return <b>false</b>. OutputExecute function will be executed + * later when other sources will be processed. + * - if all required samples are ready + * -# generate output samples + * -# mark input samples as processed + * -# return <b>true</b> to indicate that source has been processed. + * . + * . + * + * \note In some cases source must wait for external events before it is ready + * to output samples, even though all other sources are ready. For example + * DSP::u::AudioInput source must wait until the soundcard colects audio samples. + * In such cases DSP::Clock::InputNeedsMoreTime table value must be set <b>true</b> + * for the master clock related to the source output clock before output execute + * function returns <b>false</b>. + * + * \code + DSP::Clock::InputNeedsMoreTime [clock->MasterClockIndex] = true; + return false; + \endcode + * + * + * + * \section multirate_block Multirate mixed block + * In multirate blocks output clock is L/M times + * faster than input clock whre L and M integer + * relatively prime factors. + * + * \note Output clock can be obtained on the basis of input clock + * \ref DSP::Clock::GetClock "DSP::Clock::GetClock(InputClock, L_factor, M_factor)". + * + * DSP::Block::IsMultirate MUST be set to true + * and variables DSP::Block::L_factor and + * DSP::Block::L_factor MUST be set properly. + * \note Function DSP::Block::GetMultirateFactorsFromClocks can compute + * this factors and determine proper state of DSP::Block::IsMultirate. + * + * + * \section asynch_block Mixed block with asynchronous output clock + * If mixed block can have signal activated output clock. + * Then input and output processing functions are no longer synchronous + * and output clock can no longer be determined on the basis of input clock. + * + * DSP::Block::IsMultirate MUST be set to true and + * DSP::Block::L_factor and DSP::Block::L_factor variables + * should be set to -1. + * This will indicate that block is asynchronous. + * \note Function DSP::Block::GetMultirateFactorsFromClocks can compute + * this factors and determine proper state of DSP::Block::IsMultirate. + * If clocks will be detected to be synchronous correct values of L and + * M will be set instead of -1. + * + * For such blocks input samples might be invalid even if + * they have not been already processed. In such cases + * DSP::Component::RegisterForNotification should be called + * in addition to DSP::Source::RegisterClock. + * This also requires overloading of DSP::Component::Notify function + * which will be called for each clock cycle before any + * block processing. That way we can be informed that + * input samples are expected in current clock cycle. + * + * + * + * \section block_misc_ Miscellaneous + * -# block with multiple real and complex valued + * equivalent inputs (interchangeable) + * should have real valued inputs first and then complex valued ones. + * This does not apply to block where different inputs have + * different interpretation. + */ + +#ifdef __DEBUG__ + namespace DSP { + extern const vector<string> DOT_colors; + } +#endif + +// ***************************************************** // +// ***************************************************** // +//! This is main class for DSP units +/*! It serves as a base class for both processing blocks + * and sources. + * + * \todo in DSP::Component::IsOutputConnectedToThisInput implement checking whether + * each input has only one output connected (with the exception of DSP::u::Vaccum) + * + */ +class DSP::Component : public virtual DSP::name, public DSP::_connect_class +{ + friend class DSP::Block; + friend class DSP::Clock; + friend class DSP::Macro; + +/* + // connects the given output to the given input + friend bool DSP::_connect_class::connect(const DSP::output &output, const DSP::input &input, bool AllowSplit); + // connects the given already used output to the given input + friend bool DSP::_connect_class::splitconnect(const DSP::output &output, const DSP::input &input); +*/ + friend class DSP::_connect_class; + + protected: + DSP::e::ComponentType Type; + + public: + //! converts current object's pointer to DSP::Block if possible + virtual DSP::Block_ptr Convert2Block(void) + { return NULL; }; + //! converts current object's pointer to DSP::Source if possible + virtual DSP::Source_ptr Convert2Source(void) + { return NULL; }; + //! converts current object's pointer to DSP::File if possible + virtual DSP::File_ptr Convert2File(void) + { return NULL; }; + //! converts current object's pointer to DSP::Clock_trigger if possible + virtual DSP::Clock_trigger_ptr Convert2ClockTrigger(void) + { return NULL; }; + //! converts current object's pointer to DSP::u::Copy if possible + virtual DSP::u::Copy_ptr Convert2Copy(void) + { return NULL; }; + + protected: + //! Dummy block - for unconnected outputs + /*! Every unconnected output defaults to this block. + * This block does nothing or in __DEBUG__ mode + * issues warnings. + */ + static DSP::Block DummyBlock; + + + //*********************************************************************// + // COMPONENTS REGISTRATION STRUCTURES & FUNCTIONS + private: + //! Table in which all the blocks should be registered + static DSP::Component_ptr *ComponentsTable; + //! Number of slots reserved in ComponentsTable + static long int ComponentsTableSize; + //! Number of blocks registered in ComponentsTable + static long int NoOfComponentsInTable; + //! Base number of slots reserved in ComponentsTable + static const unsigned long ComponentsTableSegmentSize; + //! returns given component's index in ComponentsTable + /*! Returns -1 if component not on the list + */ + static long GetComponentIndexInTable(DSP::Component_ptr component); + + public: + //! Returns number of blocks registered in ComponentsTable + static long int GetNoOfComponentsInTable(void) + { + return NoOfComponentsInTable; + } + //! Returns component's pointer by its index + static DSP::Component_ptr GetComponent(long int index) + { + if (index < NoOfComponentsInTable) + return ComponentsTable[index]; + return NULL; + } + + //! List all registered components + /*! This is for safety precautions to indicate if any components + * are still registered when we want to call FreeClocks + * + * \warning This function works only in DEBUG mode + * + * Fixed <b>2006.07.05</b> Added function listing to log all + * blocks still on the list of the given master clock + */ + static void ListComponents(void); + //! Lists all components (if list_outputs == true also lists components outputs) + static void ListOfAllComponents(bool list_outputs = false); + //! List all registered components for algorithm related to given clock + /*! This is for safety precautions to indicate if any components + * are still registered when we want to call FreeClocks + * + * \warning This function works only in DEBUG mode + */ + static void ListComponents(DSP::Clock_ptr InputClock); + //! Checks if inputs of all blocks are connected + static void CheckInputsOfAllComponents(void); + protected: + //! Place current block (this) on the list in ComponentsTable + void RegisterComponent(void); + //! Remove current block (this) from the list in ComponentsTable + void UnregisterComponent(void); + //*********************************************************************// + + //! true when different outputs use different clocks + bool IsMultiClock; + + protected: + //! Clocks at which block outputs work + /*!Depending on IsMultiClock (only for sources) there is only one entry or NoOfOutputs entries valid, + * however memory is allocated for NoOfOutputs entries. In case of common blocks + * this is only for the sake of structure syntax checking + */ + DSP::Clock_ptr *OutputClocks; + + protected: + //Pointers for the output blocks + DSP::Block_ptr *OutputBlocks; //!one block pointer for one output + unsigned int *OutputBlocks_InputNo; //!Input number of the output block + unsigned int NoOfOutputs; //!number of outputs + + //! breaks connection with output number No + void ClearOutput(unsigned int No); + //! Sets number of outputs and initializes component's internal structures accordingly + /*! Should be used in component's constructor + * if <b>reset</b> if false previous entries in + * OutputClocks and OutputBlocks are preserved if possible + */ + void SetNoOfOutputs(unsigned int No, bool reset = true); + //! Adds additional output + /*! Returns index of added output. + * Block connection is preserved. + */ + int AddOutputLine(void); + + + //! Should be set true if the block must be destroyed automatically + /*! If AutoFree == true the block was created automatically + * (using >>new<<) by DSP_engine itself + * and must be freed automatically when the block last connected + * to this block is destroyed (in its destructor). + * + * Default: false + * + * \warning This variable is not set true automatically + */ + bool AutoFree; + + private: + //! Is set true is the component is DSP::u::Splitter created automatically + bool IsAutoSplit; + + protected: + //! Recalculates initial values + virtual void RecalculateInitials(void) {}; + + + //! Checks whether there is any output connected to given block input + /*! Returns true if there is an block with output connected to + * input number InputNo of the block OutputBlock. + * + * tempBlock is set to InputBlock + * and tempNo to its output number. + * + */ + static bool IsOutputConnectedToThisInput( + DSP::Component_ptr OutputBlock, unsigned int InputNo, + DSP::Component_ptr &tempBlock, unsigned int &tempNo); + static bool IsOutputConnectedToThisInput2( + DSP::Component_ptr OutputBlock, unsigned int InputNo, + DSP::Component_ptr &tempBlock, unsigned int &tempNo); + +// ******************************************* // +// Output connections managment // +// ******************************************* // + protected: + // //! counter containing the number of defined outputs + //unsigned int DefinedOutputsCounter; + //! pointer the the array containing pointer to defined outputs + vector <DSP::output> DefinedOutputs; + + public: + //! creates output definition for the given block + /*! Returns true if succeeds + * The same output line can be used in several DefinedOutputs. + * e.g. separate components of complex output + * and complex output itself + */ + bool DefineOutput(const string &Name, const unsigned int &OutputNo = 0); + bool DefineOutput(const string &Name, const unsigned int &OutputNo_re, const unsigned int &OutputNo_im); + bool DefineOutput(const string &Name, const vector<unsigned int> &Outputs); + //! Deletes output definition + /*! If Name.length() == 0 deletes all output definitions + */ + bool UndefineOutput(const string &Name); + //! returns output of the given name + DSP::output &Output(const string &Name); + //! returns input of the given name + virtual DSP::input &Input(const string &Name); + + protected: + //! Connects DSP::Block input to output of the current block + /*! Connects DSP::Block input number InputNo (default = 0) + * to first output of the current block. + * Inputs numbers start from 0. + * + * When succesful function returns true. When given input + * doesn't exists, function does nothing and returns false. + * + * + */ + bool SetOutput(DSP::Component_ptr Component, unsigned int InputNo=0U); //OutputNo==0; + //! Connects DSP::Block input to output of the current block + /*! Connects DSP::Block input number InputNo (default=0) + * to output number OutputNo of the current block. + * Inputs numbers start from 0. + * + * When succesful function returns true. When given input + * doesn't exists, function does nothing and returns false. + * + * Might be overloaded in descendant class + * + */ + bool SetOutput(unsigned int OutputNo, DSP::Component_ptr Block, unsigned int InputNo=0U); + + public: + //! Returns clock assigned to this block's output number OutputNo + DSP::Clock_ptr GetOutputClock(unsigned int OutputNo=0); + + unsigned int GetNoOfOutputs(void); + + protected: + // ! True if the block output clock shouln't be modified + /* ! should be true for all source blocks + * + * - default -> false + * - RegisterSource -> sets to true + * - other blocks such as SampleSelector -> sets to true + * */ + /* + bool ProtectOutputClock; + friend class DSP::u::SampleSelector; + */ + + public: + //! Resets the block to the initial state but leaves outputs and clocks untouched + virtual bool Reset(void) + { return true; }; + + public: + Component(void); + //! DSP::Component destructor + /*! Block is released from clocks' lists (only for sources) + * and memory reserved for outputs is freed + */ + virtual ~Component(void); + + public: + + #ifdef __DEBUG__ + //! Returns component name used in DOTfile (empty on failure) + string GetComponentName_DOTfile(); + /*! output_index - index of the rendered output + */ + virtual string GetComponentEdgeParams_DOTfile(const unsigned int &output_index = 0U); + //! Returns component node parameters used in DOTfile + virtual string GetComponentNodeParams_DOTfile(); + //! Returns true if ports should be used for edges + virtual bool UsePorts_DOTfile(void); + //! Writes component edges to file + void ComponentEdgesToDOTfile(std::ofstream &dot_plik, const string &this_name, + vector<bool> &UsedMacrosTable, vector<DSP::Macro_ptr> &MacrosList, + DSP::Macro_ptr DrawnMacro, unsigned int space_sep = 4); + /*! Returns source name in first_source_name if first_source_name != NULL. + * User must reserve memory for it beforehand. + * + */ + void ComponentToDOTfile(std::ofstream &dot_plik, + vector<bool> &ComponentDoneTable, long max_components_number, + vector<bool> &UsedMacrosTable, vector<DSP::Macro_ptr> &MacrosList, + vector<bool> &UsedClocksTable, vector<DSP::Clock_ptr> &ClocksList, + DSP::Macro_ptr DrawnMacro = NULL, + DSP::Clock_ptr clock_ptr = NULL); + #endif + + /****************************/ + /* Notifications support */ + /****************************/ + private: + vector<DSP::Clock_ptr> NotificationClocks; + public: + //! Function called by main clocks' processing function at the begining of each cycle + /*! It is called only for registered components. It's executed for each + * component of the active clocks before any processing is performed. + */ + virtual void Notify(DSP::Clock_ptr clock) + { + UNUSED_ARGUMENT(clock); + + #ifdef __DEBUG__ + DSP::log << DSP::e::LogMode::Error << "DSP::Component::Notify"; + DSP::log << DSP::e::LogMode::second << "Component >>" << GetName() << "<< registered for notifications but notification function not implemented !!!"; + DSP::log << endl; + #endif + return; + } + /*! Registers component for notifications with given clock. + * + * Overloaded functions DSP::Component::Notify() will be + * called for every NotifyClock cycle before sources processing. + * + * Additionaly NotifyClock is stored in NotificationClocks table + * for use in UnregisterNotifications. + */ + void RegisterForNotification(DSP::Clock_ptr NotifyClock); + //! removes block from clocks' notifications tables + /*! Removes from clocks stored in NotificationClocks + * and frees that table. + */ + void UnregisterNotifications(void); + +#ifdef __DEBUG__ + private: + //! table of macros to which this component belongs + /*! The most external macro is on the top of the table. + */ + DSP::Macro_ptr *MacrosStack; + //! length of table of macros to which this component belongs + unsigned int MacrosStackLength; + + public: + //! Check MacroStack if the components should be drawn or the macro will be drawn instead + /*! Returns pointer to the macro if it will be drawn instead of the component. + * Otherwise returns DrawnMacro. + * + * All components belonging to the DrawnMacro + * (this means they have DrawnMacro on their MacroStack) + * will be taken into consideration. If DrawnMacro is not + * on the MacroStack component must be ignored. + * + * \note If DrawnMacro == NULL, all components will be taken into + * consideration. + * + * Returns: + * - NULL - component must be drawn (is visible) + * - DrawnMacro - component must not be drawn (is invisible - outside the DrawnMacro) + * - macro pointer - returned macro must be drawn insted of the component + * . + */ + DSP::Macro_ptr DOT_DrawAsMacro(DSP::Macro_ptr DrawnMacro = NULL); +#endif +}; + +//! Class for common member functions for processing blocks which use random generator +/* This class is mainly responsible for random generator initialization. + * Prevents multiple generator initializations. + */ +class DSP::Randomization +{ + private: + //! true if random generator has been initialized + static bool Initialized; + + public: + //! \warning this function thus not call InitRandGenerator + static DSP::Float randu(void); + //! \warning this function thus not call InitRandGenerator + static void randu(unsigned int len, DSP::Float_ptr buffer); + //! \warning this function thus not call InitRandGenerator + static DSP::Float randn(void); + //! \warning this function thus not call InitRandGenerator + static void randn(unsigned int len, DSP::Float_ptr buffer); + + static void InitRandGenerator(bool force); + Randomization(void); +}; + +//! Class for common member functions for file processing blocks +/*! \note Derived class not only must define virtual functions but + * also should overide implementation od DSP::Component::Convert2File() + * This makes posible acces to DSP::File members from pointer to DSP::Component. + * + * \todo In file (input/output) blocks + * implement function GetErrorNumber + * and GetErrorName + * -> this would enable checking after creating + * block whether the file was opened + * successfully + * + */ +class DSP::File +{ + protected: + FILE *FileHandle; + //! in bits (all channels together) + unsigned long SampleSize; + long long skip_counter; + + public: + //! returns number of bytes read during last file access + virtual unsigned long GetBytesRead(void) = 0; + //! returns sampling rate of audio sample + virtual unsigned long GetSamplingRate(void) = 0; + + DSP::File_ptr GetPointer2File(void) + { return DSP::File_ptr(this); }; + + //! Changes current file position + /*! + * @param Offset file position offset in samples + * @param mode offset mode + * + * \todo add byte offset mode + * + * \note use only: ftello64, fseeko64. fgetpos, fsetpos + * (safe for files larger than 2GB) + */ + bool SetOffset(long long Offset, DSP::e::OffsetMode mode = DSP::e::OffsetMode::standard); + //! Set skip counter + /*! + * @param Offset number of samples to skip in file processing + * + * + * \note derived classes should use DSP::File::skip_counter variable + */ + virtual bool SetSkip(long long Offset) = 0; + + File(void) + { + FileHandle = NULL; + skip_counter = 0; + + SampleSize = 0; + }; + virtual ~File(void){}; +}; + +//! Class for common members for block activating signal activated clocks +/*! \note Derived class not only must define virtual functions but + * also should overide implementation od DSP::Component::Convert2ClockTrigger() + * This makes posible acces to DSP::Clock_trigger members from pointer to DSP::Component. + */ +class DSP::Clock_trigger +{ + friend class DSP::Clock; + + #ifdef __DEBUG__ + // friend void DSP::Component::ComponentToDOTfile(std::ofstream &dot_plik, + //bool *ComponentDoneTable, long max_components_number, + //DSP::Clock_ptr clock_ptr); + friend string DSP::Component::GetComponentNodeParams_DOTfile(); + #endif + + protected: + DSP::Clock_ptr SignalActivatedClock; + int SignalActivatedClock_NoOfCycles; + //! clocks index of the master clock for this block + unsigned int MasterClockIndex; + + //! returns <b>this</b> or NULL if SignalActivatedClock == NULL + Clock_trigger_ptr GetPointer2ClockTrigger(void); + + public: + Clock_trigger(void); + virtual ~Clock_trigger(void){}; +}; + +//! Class containing definition of group of inputs and outputs of a block which operate at a same clock +class clock_group +{ +private: +public: + std::vector<int> InputsIndexes; + std::vector<int> OutputsIndexes; + + DSP::Clock_ptr GroupClock; + + clock_group(void) : GroupClock(NULL) {}; + + + //Checks if the given input is in this group + bool IsInputInGroup(const int &input_no); +}; + +//! defines resampling ratio between clocks (L==-1 identifies asynchronous clocks, L==0 defined undefined ratio) +class DSP::clocks_relation +{ +public: + long L; + long M; + + //! default object's value indicates undefined ratio + clocks_relation(void): L(0), M(0) {}; + clocks_relation(const long &L_in, const long &M_in): L(L_in), M(M_in) {}; +}; + +/*! + * Example of use in block constructor: + * ClockGroups.AddInput2Group("input", Input("in")); + * ClockGroups.AddOutput2Group("output", Output("out")); + * ClockGroups.AddInput2Group("output", Input("eps")); + * ClockGroups.AddClockRelation("input", "output", L_factor, M_factor); + */ +class DSP::clock_groups +{ +public: + std::map<std::string, clock_group > groups; + +// std::vector<clocks_relation> clocks_relations; + // clocks_relations[group_name_src, group_name_dest] = clocks_ratio + std::map<std::string, std::map<std::string, DSP::clocks_relation > > clocks_relations; + + //! returns name of the group to which given input belongs (note: input can belong only to one group) + std::string FindGroupName4Input(int input_index); + std::string FindGroupName4Output(int output_index); + + //! returns clock for the given input based on the clock of the reference group with given name + DSP::Clock_ptr FindClock4Input(const std::string &group_name, const int &input_index); + + //! returns clock for the given output based on the clock of the reference group with given name + DSP::Clock_ptr FindClock4Output(const std::string &group_name, const int &output_index); + +// /*! dodanie grupy lub nadpisanie zegara istniej�cej grupy +// */ +// void SetGroupClock(const std::string &name, const DSP::Clock_ptr &clock); + + /*! Adds inputs from index_start to index_end. + * + * If necessary creates new clocks group + */ + void AddInputs2Group(const std::string &name, const int &index_start, const int &index_end); + void AddInput2Group(const std::string &name, const int &index); + void AddInput2Group(const std::string &name, const DSP::input &input); + void AddOutputs2Group(const std::string &name, const int &index_start, const int &index_end); + void AddOutput2Group(const std::string &name, const int &index); + void AddOutput2Group(const std::string &name, const DSP::output &output); + + void AddClockRelation(const std::string &parent_group, const std::string &child_group, const long &L, const long &M); + +// /*! dodanie relacji pomi�dzy zegarami dw�ch grup lub nadpisanie istniej�cej relacji +// */ +// void SetGroupsRelation(const std::string &parents_name, const std::string &childs_name, const int &L, const int &M); +// +// DSP::Clock_ptr GetChildsClock(const std::string &parents_name); +// DSP::Clock_ptr GetParentsClock(const std::string &childs_name); +}; + +// ***************************************************** // +// ***************************************************** // +//! This is main class for DSP processing blocks +/*! \todo_later Source blocks must always check wether the given Clock pointer + * is valid. + * + * \todo_later No NULL clock pointers should be allowed at construction time. + * User clock should explicitly be defined by the user. + * + * Fixed <b>2005.02.13</b> while creating error messages dynamicaly + * allocated strings (tekst) should be used instead of static ones + * + * + * \todo_later Stworzyc macro CreateDSPblock(Nazwa, parameters); + * Ktore tworzylo by blok o takiej nazwie oraz funkcje SetName + * jednoczesnie ustawialoby mu taka nazwe (pytanie co z kontrola poprawnosci + * parametrow oraz ronymi listami parametrow + * + * \todo Precise control other clocks correctness should be established when + * blocks are connected + * + * \todo_later Vectorized complex or real valued input and outputs in blocks + * Create descendant class from DSP::Blocks + * + * + * + * \todo_later Check whether this is still actual: + * DSP_Buffor <- bufor wydajcy dane zgodnie z zegarem wyjsciowym + * przyjmujacy dane asynchronicznie (niezalenie od zegara wyjciowego + * jezeli wystpi adanie prbki wyjciowej po pobraniu ostatniej + * probki wyjciowej na wyjscie powinna by podana ta sama probka co + * poprzednio (PROBLEM: zegar wyjciowy moze by wywolany + * przed wywolaniem bloczka podajacego warto wejciowa, + * ale rowniez moze by tak, ze wartosc wejciowa nie bedzie + * podana na wejcie w tym cyklu zegara) + */ +class DSP::Block : public virtual DSP::Component +{ + friend class DSP::Component; +// friend class DSP::Clock; + +// friend bool DSP::_connect_class::splitconnect(const DSP::output &output, const DSP::input &input); + friend class _connect_class; + + friend class DSP::Macro; +// friend void DSP::Macro::MacroEdgesToDOTfile(std::ofstream &, char *, unsigned int); + + + public: + //! converts current object's pointer to DSP::Source is possible + Block_ptr Convert2Block(void) + { return (Block_ptr)this; }; //??? + +// ****************************************** // +// Input connections management // +// ****************************************** // + protected: + // //! counter containing the number of defined inputs + //unsigned int DefinedInputsCounter; + //! pointer the the array containing pointer to defined inputs + vector<DSP::input> DefinedInputs; + + public: + //! creates input definition for the given block + /*! Returns true if succeeds. + */ + bool DefineInput(const string &Name, const unsigned int &InputNo = 0); + bool DefineInput(const string &Name, const unsigned int &InputNo_re, const unsigned int &InputNo_im); + bool DefineInput(const string &Name, const vector <unsigned int> &Inputs); + //! Deletes input definition + /*! If Name == NULL deletes all input definitions + */ + bool UndefineInput(const string &Name); + //! returns input of the given name + DSP::input &Input(const string &Name); + + protected: + //! Clocks at which each input works + /*! This is only for the sake of structure syntax checking */ + vector<DSP::Clock_ptr> InputClocks; + + DSP::clock_groups ClockGroups; + + //! Stores for the current block the clock associated with its given input. + /*! The clock is then compared with clock for the other inputs or outputs + * (especially mixed blocks outputs). If it is also possible (if the output + * clock can be determined) the output clock should be also stored. + * If the output Clock is updated Input clock of blocks connected to + * that output should also be updated. + * + * This function in general is block dependent. + */ + virtual void SetBlockInputClock(unsigned int InputNo, DSP::Clock_ptr InputClock); + DSP::Clock_ptr GetBlockInputClock(unsigned int InputNo); + + //! Number of inputs + /*! This variable should not be set directly! + * Use DSP::Block::SetNoOfInputs instead. + */ + unsigned int NoOfInputs; + + //! Number if inputs processed in current cycle + unsigned int NoOfInputsProcessed; + + //! Number of real inputs (these are first inputs) + unsigned int NoOfRealInputs; + //! Is first complex input's number odd + bool IsComplex_real_odd; + + //! Contains number of inputs connected using DSP::Block::SetOutput + unsigned int NoOfInputsConnected; + //! Initial number if inputs processed = NoOfInputs - number of constant inputs + unsigned int InitialNoOfInputsProcessed; + //! Returns true when the block must be destroyed automaticaly + /*! True if AutoFree == true and last input was cleared + * or all inputs were allready cleared (NoOfInputs-InitialNoOfInputsProcessed). + * + * \warning Must be called only once per input, and only when + * output connected to the input is cleared + */ + bool ClearInput(unsigned int InputNo); + + //! True if block is using constant input variables + /*! DSP::Block::ConstantInputValues and + * DSP::Block::IsConstantInput + * + * \note This variable is set by DSP::Block::SetConstInput. + * See also DSP::Block::BlockAllowsForConstantInputs. + */ + bool IsUsingConstants; + //! finds index of the input connected to given output of this block + /*! returns + * - output index if block had more than one output + * - FO_TheOnlyOutput if it is the only output + * - FO_NoOutput if no block was found + * . + */ + unsigned int FindOutputIndex_by_InputIndex(unsigned int InputIndex); + //! True is block supports use of constant inputs. + /*! \note This variable is set by DSP::Block::SetNoOfInputs. + * See also DSP::Block::IsUsingConstants. + */ + bool BlockAllowsForConstantInputs; + //! Values for constant inputs + vector<DSP::Float> ConstantInputValues; + //! true is given value is constant + vector<bool> IsConstantInput; + + //!Sets number of inputs + /*!Parameters are: number of real inputs, number of complex inputs + * and bool constant telling whether the block allows constant inputs. + * This function should be used instead of setting the DSP::Block::NoOfInputs + * directly. + */ + void SetNoOfInputs(unsigned int No_real, unsigned int No_complex, bool AllowForConstantInputs); + //!Sets number of inputs (see: void SetNoOfInputs(int, int, bool)) + void SetNoOfInputs(unsigned int No_real, bool AllowForConstantInputs); + + + //! Set if the block is multirate block (output clock differs from input clock) + bool IsMultirate; +// //! Interpolation (L) and decimation (M) factor +// int L_factor, M_factor; + + //! input and output clocks groups definitions with relations between these clocks + std::vector<clock_group> clocks_groups; + + //! returns true if block is Multirate and fills L and M with proper interpolation and decimation factors + /*! If clocks are asynchronous L and M will be set -1. + * On the other hand is clocks are detected as synchronous + * correct values of L and L will be set. + * + * Function output should be set to IsMultirate variable. + * + * If ClocksShouldBeSynchronous is <b>true</b> + * error message will be generated if asynchronous + * clocks are detected. + */ + bool GetMultirateFactorsFromClocks(DSP::Clock_ptr InputClock, DSP::Clock_ptr OutputClock, + long &L, long &M, bool ClocksShouldBeSynchronous); + + + public: + // bool Get_IsMultiClock(void) + // { return IsMultiClock; } +// int Get_L_factor() +// { return L_factor; } +// int Get_M_factor() +// { return M_factor; } + + unsigned int GetNoOfInputs(void); + + /*! Assigns constant values to selected inputs + * (output connections to this inputs shouldn't be allowed) + * Initial sum value is calculated on this basis + * and NoOfInputs processed is also initiated acordingly. + * + * Should be used before connecting any outputs + * + * Replaces obsolete function: + * bool SetConstInput(int InputNo, DSP::Float value); + */ + bool SetConstInput(const string &InputName, DSP::Float value); + /*! Indicates given input as constant value + * InputNo -> real_value + * InputNo+1 -> imag_value + * (no coutput can be connected to it) + * + * Should be used before connecting any outputs + * + * Replaces obsolete function: + * bool SetConstInput(int InputNo, DSP::Float real_value, DSP::Float imag_value); + */ + bool SetConstInput(const string &InputName, DSP::Float real_value, DSP::Float imag_value); + bool SetConstInput(const string &InputName, DSP::Complex value) + { + return SetConstInput(InputName, value.re, value.im); + } + + //! Checks whether to the given input we can connect output + /*! Prevents from connecting outputs to constant inputs, + * nonexistent inputs and inputs already used by outputs + * + * \todo_later add this to description + */ + virtual bool IsInputAvailable(unsigned int InputNo=0); + + public: + //! Input processing callback funtion pointer for Processing blocks + DSP::Block_Execute_ptr Execute_ptr; + + //!Processing command for Processing blocks + /*! value is put on input number InputNo. + * If no output connected value redirected to DSP::Block::DummyBlock + */ + static void DummyExecute(INPUT_EXECUTE_ARGS) + { + UNUSED_ARGUMENT(InputNo); + UNUSED_ARGUMENT(value); + + #ifndef __DEBUG__ + UNUSED_ARGUMENT(block); + #else + stringstream tekst; + if (block == &DummyBlock) + { + tekst << "WARNING: Unconnected output detected (" << Caller->GetName() << ")"; + } + else + { + tekst << "WARNING: Block uses DummyExecute. Check block constructor if Execute_ptr is set correctly (" + << Caller->GetName() << ")"; + } + DSP::log << DSP::e::LogMode::Error << "DSP::Block::Execute" << DSP::e::LogMode::second << tekst.str() << endl; + #endif + } + + public: + //! Basic DSP::Block constructor + /*! Outputs and input numbers are set to zero. + */ + Block(void); + //! Basic DSP::Block destructor + /*! Block is released from clocks' lists (only for sources) + * and memory reserved for outputs is freed + */ + virtual ~Block(void); +}; + +// ***************************************************** // +// ***************************************************** // +//! This is main class for DSP source blocks +/*! \todo_later Move basic source registration in ParentrClock + * from descendant block into DSP::Source itself + * so only more complicated cases will need it + * done explicitly + */ +class DSP::Source : public virtual DSP::Component +{ + friend class DSP::Component; + friend class DSP::Clock; + + public: + //! converts current object's pointer to DSP::Source is possible + Source_ptr Convert2Source(void) + { return Source_ptr(this); }; + + private: + // // ! Indicates that source is always ON + // /* ! This field is taken into account in DSP::Clock::ProcessSources method + // */ + // bool IsActive; + // // ! Indicates that this source is controlled by DSP::u::BranchSelector + // bool IsControlled; + // // ! Indicates that this source knows its current state and doesn't need to wait for state update. + // /* ! It is only valid if IsControlled == true + // * + // * \note must be updated after notifycation from DSP::u::BranchSelector + // * and after each source execution + // */ + // bool IsSourceStateReady; + // // ! number of fundamental clock cycles of SourceState validity time + // /* ! Must be updated each time Controlled source is executed successfully + // * together with IsSourceStateReady. + // */ + // long int activation_time_length; + // // ! Indicates that source is ON when it IsControlled + // /* ! This field is taken into account in DSP::Clock::ProcessSources method + // */ + // bool IsControlledActive; + // // ! Updates IsSourceStateReady and activation_time_length + // /* ! \note Must be called after the Controlled source has just been processed + // */ + // void UpdateSourceState(void); + + protected: + //! calls DSP::Component::SetNoOfOutputs and after that performs source specific actions + void SetNoOfOutputs(unsigned int No); + //one SourceReady and one OutputClocks pointer per one output + //If unit is not source OutputClocks[0] == NULL + bool *SourceReady; + + //! Unregister source from OutputClocks lists + void UnregisterOutputClocks(void); + void RegisterOutputClock(DSP::Clock_ptr OutputClock, unsigned int output_index = 0U); + + public: + //! Output processing callback function pointer for sources + Source_Execute_ptr OutputExecute_ptr; + + //! Processing command for Source blocks + /*! returns true if source was ready and processed all commands. + * Input variable clock gives pointer to the clock revoking + * this function. + */ + static bool DummyExecute(OUTPUT_EXECUTE_ARGS) + { + UNUSED_RELEASE_ARGUMENT(source); + UNUSED_DEBUG_ARGUMENT(clock); + + #ifdef __DEBUG__ + DSP::log << DSP::e::LogMode::Error << "DSP::Block::Execute" + << DSP::e::LogMode::Error + << "WARNING: Source uses DummyExecute. Check source constructor if OutputExecute_ptr is set correctly (" + << source->GetName() << ")" << endl; + #endif + return true; + } + + // // ! Sets Activates/Deactivates source. + // /* ! If TurnOn == true the field is set to true + // * and the source will be processed in subsequent clock cycles. + // * + // * If ParentClockOfTheControler != NULL this source activation is controlled + // * by DSP::u::BranchSelector descendant and given state is valid only + // * for duration of the ParentClockOfTheControler fundamental cycle. + // */ + // void SetState(bool TurnOn=true, DSP::Clock_ptr ParentClockOfTheControler=NULL); + + public: + //! Basic DSP::Source constructor + /*! Outputs and input numbers are set to zero. + */ + Source(void); + //DSP::Source(DSP::Clock_ptr ParentClock); + virtual ~Source(void); +}; + +//! Class storing current stack of macros +/*! On the basis of this stack user + * can determine how the macros are nested + * at the moment. + * + * \note Macro stack copy is stored with every component. + * This information determines to which macros given component belongs. + * It is done only in debug mode. + */ +class DSP::MacroStack +{ + friend class DSP::Macro; + + private: + //! table of active macros + /*! The most external macro is on the top of the table. + * + * Active macro is the macro which is in initialization state. + */ + static DSP::Macro_ptr *Stack; + //! length of table of active macros + static unsigned int Length; + + //! List of all existing macros + static DSP::Macro_ptr *List; + //! length of list of existing macros + static unsigned int ListLength; + + //! adds this macro at the bottom of Stack table + static void AddMacroToStack(DSP::Macro_ptr macro); + //! removes this macro from Stack table + /*! macro is expected at the bottom of the stack + */ + static void RemoveMacroFromStack(DSP::Macro_ptr macro); + + //! adds this macro at the bottom of List table + static void AddMacroToList(DSP::Macro_ptr macro); + //! removes this macro from List table + /*! macro can be anywhere on the list + */ + static void RemoveMacroFromList(DSP::Macro_ptr macro); + + public: + //! Returns current macro stack + /*! Used in DSP::Component constructor to determine + * to which macros given component belongs. + * + * \note MacrosStack will be overwritten with new value + * which will point to the macros table allocated + * inside this function. + * + * \warning The user must free MacroStack table allocated + * by this function on his own. + */ + static unsigned int GetCurrentMacroStack(DSP::Macro_ptr *&MacrosStack); + + //! Returns current macro list in MacroList + /*! + * \note MacrosList will be overwritten with new value + * which will point to the macros table allocated + * inside this function. + * + * \warning The user must free MacroList table allocated + * by this function on his own. + */ + static unsigned int GetCurrentMacroList(vector<DSP::Macro_ptr> &MacrosList); +}; + +//! User can derive class from this block to group several DSP components into single macro component +/*! Macro component can be used in the same way as any over component, + * but it will be implemented as the group of DSP components + * defined inside the decendant to DSP::Macro class. + * + * All macro external inputs and outputs must be done + * through MacroInput and MacroOutput objects. + * User can create his own naming convention. + * + * Macro inputs and outputs can be accesed by + * -# External macro input ==> DSP::Macro::Output + * -# External macro output ==> DSP::Macro::Input + * -# Internal output of the macro input ==> DSP::Macro::InputOutput + * -# Internal input of the macro output ==> DSP::Macro::OuputInput + * . + * + * \note Creating inputs and outputs naming convention remember that + * -# External macro input == input of the MacroInput component + * -# External macro output == output of the MacroOutput component + * -# Internal output of the macro input == output of the MacroInput component + * -# Internal input of the macro output == input of the MacroOutput component + * . + * + * \todo DOT mode to create scheme with macro as the single component + * or as the separate objects being part of the macro object. + */ +class DSP::Macro : public virtual DSP::name +{ + #ifdef __DEBUG__ + friend void DSP::Component::ComponentEdgesToDOTfile(std::ofstream &, const string &, + vector<bool> &, vector<DSP::Macro_ptr> &, DSP::Macro_ptr, unsigned int); + #endif + + private: + //! true if macro initialization is in progress + /*! \todo DSP::Component::CheckInputsOfAllComponents must also check + * if all macro initialization is finished for all macros + * in MacroStack. + */ + bool MacroInitializationOn; + + unsigned int NoOfInputs; + unsigned int NoOfOutputs; + + #ifdef __DEBUG__ + private: + //! determines how macro will be represented on DOT graph + /*! Default value == DSP::e::DOTmode::DOT_macro_wrap. + */ + DSP::e::DOTmode DOTmode; + public: + //! true if macro must be drawn instead of macro components + bool DOT_DrawMacro(void); + //! writes macro's node and edges to the DOT file + /*! If this == DrawnMacro draw macro input and output blocks + */ + void MacroToDOTfile(std::ofstream &dot_plik, DSP::Macro_ptr DrawnMacro); + #endif + + + protected: + DSP::u::Copy_ptr MacroInput_block; + DSP::u::Copy_ptr MacroOutput_block; + + //! returns internal output of the macro input of the given name + DSP::output &MacroInput(const string &Name); + //! returns internal input of the macro output of the given name + DSP::input &MacroOutput(const string &Name); + + public: + //! returns macro output of the given name + DSP::output &Output(const string &Name); + //! returns external macro input of the given name + DSP::input &Input(const string &Name); + + //! Returns macro input line number connected to the given macro block input + /*! Returns FO_NoInput if not connected to the macro input + */ + unsigned int GetMacroInputNo(DSP::Component_ptr output_block, unsigned int output_block_input_no); + + //! creates input definition for macro input (internal and external) + /*! Returns true if succeeds. + */ + bool DefineInput(const string &Name, const unsigned int &InputNo = 0); + bool DefineInput(const string &Name, const unsigned int &InputNo_re, const unsigned int &InputNo_im); + bool DefineInput(const string &Name, const vector<unsigned int> &Inputs); + //! Deletes input definition + bool UndefineInput(const string &Name = ""); + + //! creates output definition for macro output (internal and external) + /*! Returns true if succeeds + */ + bool DefineOutput(const string &Name, const unsigned int &OutputNo = 0); + bool DefineOutput(const string &Name, const unsigned int &OutputNo_re, const unsigned int &OutputNo_im); + bool DefineOutput(const string &Name, vector<unsigned int> &Outputs); + //! Deletes output definition + bool UndefineOutput(const string &Name = ""); + + //! Returns clock assigned to macro external output number OutputNo + DSP::Clock_ptr GetOutputClock(unsigned int OutputNo=0); + + protected: + //! Function call from macro constructor + /*! Creates MacroInput and MacroOutput objects + * with given input and output lines number. + * + * All user macro components and connections MUST + * be after call to this function and before + * call to DSP::Macro::MacroInitFinished. + * + * Order of the execution <b>MacroInitStarted</b> + * -# Macro stack update (add macro to stack) + * -# MacroInput and MacroOutput creation + * -# Mark macro initialization as in progress + * . + */ + void MacroInitStarted(void); + //! Function call from macro initialization finish + /*! + * Order of the execution <b>OnMacroDelete</b> + * -# Macro stack update (remove macro from stack) + * -# Mark macro initialization as finished + * . + * + * \note No macro components should be created after call to this function. + */ + void MacroInitFinished(void); + + public: + //! Creates macro component basic container + /*! Macro list update (add macro to the list) + * + * \note All macro components should be created in derived class destructor + * between calls to DSP::Macro::MacroInitStarted and DSP::Macro::MacroInitFinished. + */ + Macro(const string ¯o_name, + unsigned int NoOfInputs_in, + unsigned int NoOfOutputs_in); + //! Macro container clean up + /*! Destroys MacroInput and MacroOutput objects. + * + * Macro list update (remove macro from the list) + * + * \note All macro components should be deleted in derived class destructor. + */ + virtual ~Macro(void); + + public: + void SetDOTmode(DSP::e::DOTmode mode = DSP::e::DOTmode::DOT_macro_wrap) + { + UNUSED_RELEASE_ARGUMENT(mode); + + #ifdef __DEBUG__ + DOTmode = mode; + #endif + } + DSP::e::DOTmode GetDOTmode(void) + { + #ifdef __DEBUG__ + return DOTmode; + #else + return DSP::e::DOTmode::DOT_macro_inactive; + #endif + } + + #ifdef __DEBUG__ + private: + //! Returns macro node parames used in DOTfile + string GetMacroNodeParams_DOTfile(); + //! used in macro graph to draw input node + string GetMacroInputNodeParams_DOTfile(); + //! used in macro graph to draw output node + string GetMacroOutputNodeParams_DOTfile(); + //! Draws macro node edges + string GetMacroEdgeParams_DOTfile(const unsigned int &output_index); + bool UsePorts_DOTfile(void); + //! Writes macro outgoing edges to file + void MacroEdgesToDOTfile(std::ofstream &dot_plik, const string ¯o_name, + DSP::Macro_ptr DrawnMacro, unsigned int space_sep = 4); + void MacroInputEdgesToDOTfile(std::ofstream &dot_plik, const string ¯o_input_name, + DSP::Macro_ptr DrawnMacro, unsigned int space_sep = 4); + void MacroOutputEdgesToDOTfile(std::ofstream &dot_plik, const string ¯o_output_name, + DSP::Macro_ptr DrawnMacro, unsigned int space_sep = 4); + + //! Returns macro name used in DOTfile + string GetMacroName_DOTfile(); + #endif +}; + +/**************************************************/ +//! Delay element implemented in mixed mode (unit-source) +/*! \warning Necessary for digital feedback loop !!! + * + * Inputs and Outputs names: + * - Output: + * -# "out" (vector of all outputs) + * -# "out1", "out2", ... + * -# "out.re" == "out1" + * -# "out.im" == "out2" + * . + * - Input: + * -# "in" (vector of all inputs) + * -# "in1", "in2", ... + * -# "in.re" == "in1" + * -# "in.im" == "in2" + * . + */ +class DSP::u::LoopDelay : public DSP::Block, public DSP::Source +{ + private: + unsigned int *Delay; + DSP::Float **State; + bool *IsOutputProcessed, *IsInputProcessed; + DSP::Float *tempInput; + + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + static bool OutputExecute_multi(OUTPUT_EXECUTE_ARGS); + + static void InputExecute(INPUT_EXECUTE_ARGS); + static void InputExecute_multi(INPUT_EXECUTE_ARGS); + + public: + LoopDelay(DSP::Clock_ptr ParentClock, unsigned int delay=1U, unsigned int inputs_no = 1U); + virtual ~LoopDelay(void); + + //! Sets internal state for delay line related to given input + /*! \param InputName - must be name of real valued input line + * \param size - number of elements in state_buffer; must be + * equal to size of the delay + * \param state_buffer - buffer with initial values + */ + bool SetState(const string &InputName, unsigned int size, DSP::Float_ptr state_buffer); + //! Sets internal state for delay line related to given input + /*! State buffer size (block delay) must equal one. + * \param InputName - must be name of real valued input line + * \param state_buffer_value - buffer with initial values + */ + bool SetState(const string &InputName, DSP::Float state_buffer_value); +}; + +//! Delay element implemented in processing mode +/*! \warning Cannot separate processing in digital feedback loop !!! + * + * Inputs and Outputs names: + * - Output: + * -# "out" (vector of all outputs) + * -# "out1", "out2", ... + * -# "out.re" == "out1" + * -# "out.im" == "out2" + * . + * - Input: + * -# "in" (vector of all inputs) + * -# "in1", "in2", ... + * -# "in.re" == "in1" + * -# "in.im" == "in2" + * . + */ +class DSP::u::Delay : public DSP::Block +{ + private: + unsigned int delay; + DSP::Float **State; + //! current index in buffer + unsigned int *index; + + //! version for Delay == 0 + static void InputExecute_D0(INPUT_EXECUTE_ARGS); + static void InputExecute_D0_multi(INPUT_EXECUTE_ARGS); + //! version for Delay == 1 + static void InputExecute_D1(INPUT_EXECUTE_ARGS); + static void InputExecute_D1_multi(INPUT_EXECUTE_ARGS); + //! version with memcpy + static void InputExecute(INPUT_EXECUTE_ARGS); + static void InputExecute_multi(INPUT_EXECUTE_ARGS); + //! version with cyclic buffer + static void InputExecute_with_cyclic_buffer(INPUT_EXECUTE_ARGS); + static void InputExecute_with_cyclic_buffer_multi(INPUT_EXECUTE_ARGS); + public: + //! DSP::u::Delay block constructor + Delay(unsigned int delay_in = 1, unsigned int InputsNo = 1, bool IsBufferCyclic = true); + virtual ~Delay(void); +}; + +/**************************************************/ +//! Outputs input value to multiple outputs +/*! Inputs and Outputs names: + * - Output: + * -# "out1", "out2", ... (real or complex valued) + * -# "out1.re", "out2.re", ... (real components)\n + * "out1.im", "out2.im", ... (imag components if exists) + * - Input: + * -# "in" (real or complex valued) + * -# "in.re" (real component)\n + * "in.im" (imag component if exists) + */ +class DSP::u::Splitter : public DSP::Block +{ + private: + static void InputExecute(INPUT_EXECUTE_ARGS); + + #ifdef __DEBUG__ + private: + bool UsePorts_DOTfile(void); + string GetComponentNodeParams_DOTfile(); + string GetComponentEdgeParams_DOTfile(const unsigned int &output_index); + #endif + + public: + Splitter(unsigned int No=2); //number of outputs + Splitter(bool IsInputComplex, unsigned int No=2); //number of outputs + ~Splitter(void); +}; + +/**************************************************/ +//! Gets value from selected input and sends it to the selected output +/*! There can be only one input and/or output. In addition + * this unit can be used to break processing line - no output + * would be processed. + * + * If UseSelectorInputs is true additional inputs are available: + * "input_selector" & "output_selector". Values from these inputs + * indicate currently selected input/output. + * Inputs/outputs are selected by numbers (floor from the actual input value) + * 0, 1, 2, ... selects input/ouput number 1, 2, 3 ... (0 means "in1"/"out1" and so on). + * + * \note When input and/or output index is out of range + * output sample will not be generated. + * + * Inputs and Outputs names: + * - Output: + * -# "out1", "out2", ... (real or complex valued) + * -# "out1.re", "out2.re", ... (real components)\n + * "out1.im", "out2.im", ... (imag components if exists) + * - Input: + * -# "in1", "in2", ... (real or complex valued) + * -# "in1.re", "in2.re", ... (real components)\n + * "in1.im", "in2.im", ... (imag components if exists) + * + * Input/Output numbers must be selected directly using DSP::u::Switch::Select + * + * \todo Implement inputs: + * -# "input_selector" index of the selected input + * -# "output_selector" index of the selected output + * . + */ +class DSP::u::Switch : public DSP::Block +{ + private: + void Init(bool IsInputComplex, //! if true inputs are complex, otherwise real + unsigned int InputsNo=1U, //! number of inputs to select from + unsigned int OutputsNo=1U //! number of outputs to select from +// bool UseSelectorInputs=false //! if true additional inputs "input_selector" & "output_selector" are available + ); + + //! Number of signal components per input/output (for real == 1, for complex == 2) + unsigned int ValuesPerOutput; + //! Index of additional input for input/output selection (FO_NoInput and FO_NoOutput means not available) + unsigned int InputSelectionInd, OutputSelectionInd; + //! Index of the last input line (with the exeption of additional inputs for input/output selection) + unsigned int LastInputInd; + //! Index of the selected input and output + unsigned int SelectedInputNo, SelectedOutputNo; + //! Maximum allowed index of the selected input and output (index start from zero!) + unsigned int MaxSelectedInputNo, MaxSelectedOutputNo; + //! Minimum allowed index of the selected input and output (zero or FO_NoInput) + unsigned int MinSelectedIndexNo; + + // vector for storing input values before all are available and output is generated + DSP::Float_ptr State; + + /*! \todo_later Consider processing Output as soon as SelectedInputs are avaiable + * \todo_later Consider storing only SelectedInputs the rest could be ignored + */ + static void InputExecute(INPUT_EXECUTE_ARGS); + + public: + Switch(unsigned int InputsNo=1U, //! number of inputs to select from + unsigned int OutputsNo=1U //! number of outputs to select from +// bool UseSelectorInputs=false //! if true additional inputs "input_selector" & "output_selector" are available + ); + Switch(bool IsInputComplex, //! if true inputs are complex, otherwise real + unsigned int InputsNo=1U, //! number of inputs to select from + unsigned int OutputsNo=1U //! number of outputs to select from +// bool UseSelectorInputs=false //! if true additional inputs "input_selector" & "output_selector" are available + ); + ~Switch(void); + + void Select(unsigned int InputIndex, unsigned int OutputIndex); +}; + +/**************************************************/ +//! Multiplies input value by given constant +/*! Inputs and Outputs names: + * - Output: + * -# "out_all" - all output lines + * -# "out" - first output (real or complex) + * -# "out.re", /n + * "out.im" + * -# "out1", "out2", ... - consecutive outputs (real or complex) + * -# "out1.re", "out2.re", .../n + * "out1.im", "out2.im", ... + * - Input: + * -# "in_all" - all input lines + * -# "in" - first input (real or complex) + * -# "in.re", /n + * "in.im" + * -# "in1", "in2", ... - consecutive inputs (real or complex) + * -# "in1.re", "in2.re", .../n + * "in1.im", "in2.im", ... + */ +class DSP::u::Amplifier : public DSP::Block +{ + private: + //! index variable for input execute + unsigned int ind; + //! temporary variable for storing input for InputExecute_cplx_inputs_with_cplx_factor + DSP::Float_ptr temp_inputs; + + bool IsGainComplex; + DSP::Float Coeficient; + DSP::Complex CplxCoeficient; + + static void InputExecute_one_real_input_with_real_factor(INPUT_EXECUTE_ARGS); + static void InputExecute_real_factor(INPUT_EXECUTE_ARGS); + static void InputExecute_real_inputs_with_cplx_factor(INPUT_EXECUTE_ARGS); + static void InputExecute_cplx_inputs_with_cplx_factor(INPUT_EXECUTE_ARGS); + + public: + Amplifier(DSP::Float alfa, unsigned int NoOfInputs_in = 1, bool AreInputsComplex = false); + //! Amplifier with complex gain factor (changes amplitude and phase) + /*! \param NoOfInputs_in - number of real or complex inputs + * \param AreInputsComplex - if true, inputs are complex + * \param alfa - amplification coefficient + */ + Amplifier(DSP::Complex alfa, unsigned int NoOfInputs_in = 1, bool AreInputsComplex = false); + ~Amplifier(void); + + //! changes amplification factor + void SetGain(DSP::Float gain); + //! changes amplification factor + void SetGain(DSP::Complex gain); +}; + +/**************************************************/ +//! Calculates given power of the input signal +/*! Inputs and Outputs names: + * - Output: + * -# "out" (real or complex valued) + * -# "out.re", "out.im" + * . + * - Input: + * -# "in" (real or complex valued) + * -# "in.re", "in.im" + * . + * . + * There are different implementation for + * - power 2 + * - integer power (other than 2) + * - power with the real factor (only for real input signals) + * . + */ +class DSP::u::Power : public DSP::Block +{ + private: + int IntFactor; + DSP::Float RealFactor; + + //! index variable for InputExecute functions + int ind; + //! temporary variable for complex input signal + DSP::Complex in_value; + //! temporary variable for complex output signal + DSP::Complex out_value; + + static void InputExecute_Power2_real(INPUT_EXECUTE_ARGS); + static void InputExecute_Power2_cplx(INPUT_EXECUTE_ARGS); + static void InputExecute_PowerInt_real(INPUT_EXECUTE_ARGS); + static void InputExecute_PowerInt_cplx(INPUT_EXECUTE_ARGS); + static void InputExecute_PowerReal_real(INPUT_EXECUTE_ARGS); + //static void InputExecute_PowerReal_cplx(DSP::Block *block, int InputNo, DSP::Float value, DSP::Component *Caller); + + public: + Power(int factor); + Power(bool IsComplex, int factor); + Power(DSP::Float factor); + Power(bool IsComplex, DSP::Float factor); + ~Power(void); +}; + +/**************************************************/ +//! Addition block +/*! Adds up all input values and outputs the result + * Real and complex valued inputs are allowed. + * If there is any complex valued input the output is + * also complex valued , otherwise the output is + * real valued. + * + * Constant inputs can also be defined + * using DSP_Addition::SetConstInput(). + * This should be done before any outputs are connected + * to this block inputs. + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real or complex valued) + * -# "out.re" (real component)\n + * "out.im" (imag component if exists) + * - Input: + * -# "real_in1", "real_in2", ... - real inputs + * -# "cplx_in1", "cplx_in2", ... - complex inputs + * -# "cplx_in1.re", ... - real part of complex input + * -# "cplx_in1.im", ... - imaginary part of complex input + * -# "in1", "in2", ... - real or complex inputs + * -# "in1.re", "in2.re", ... - real components of inputs + * -# "in1.im", "in2.im", ... - imaginary components of inputs (if they exist) + * . + * For block that has one real input and two complex inputs + * we will have following predefined names: + * - "real_in1", "cplx_in1", "cplx_in2" + * - "cplx_in1.re", "cplx_in1.im", "cplx_in2.re", "cplx_in2.im" + * - "in1", "in2", "in3" + * - "in1.re", "in2.re", "in2.im", "in3.re", "in3.im" + * . + */ +class DSP::u::Addition : public DSP::Block +{ + private: +// int NoOfInputsProcessed; +// int NoOfInputs; + DSP::Float State_real, State_imag; + + DSP::Float_ptr RealWeights; + DSP::Complex_ptr CplxWeights; + + //! Initial Sum value = 0.0 if no constant inputs (real part) + DSP::Float InitialSum_real; + //! Initial Sum value = 0.0 if no constant inputs (imaginary part) + DSP::Float InitialSum_imag; + + //! Standard initialization + /*! \param ForceCplxOutput - if true forces block output to be complex + * even though all inputs are real. This should be used with + * complex weights. + * \param NoOfComplexInputs_in number of complex valued inputs + * \param NoOfRealInputs_in number of real valued inputs + */ + void Init(unsigned int NoOfRealInputs_in, unsigned int NoOfComplexInputs_in, bool ForceCplxOutput = false); + + //! Recalculates initial values + void RecalculateInitials(void); + + static void InputExecute(INPUT_EXECUTE_ARGS); + static void InputExecute_RealWeights(INPUT_EXECUTE_ARGS); + static void InputExecute_CplxWeights(INPUT_EXECUTE_ARGS); + + public: + /*! NoOfRealInputs <- number of real valued inputs + * first NoOfRealInputs are treated as real valued inputs + * this real inputs are followed by complex valued ones + */ + Addition(unsigned int NoOfRealInputs_in=2, unsigned int NoOfComplexInputs_in=0); //number of inputs + Addition(unsigned int NoOfRealInputs_in, DSP::Float_ptr weights); + Addition(unsigned int NoOfRealInputs_in, DSP::Complex_ptr weights); + Addition(unsigned int NoOfRealInputs_in, unsigned int NoOfComplexInputs_in, DSP::Float_ptr weights); + Addition(unsigned int NoOfRealInputs_in, unsigned int NoOfComplexInputs_in, DSP::Complex_ptr weights); + ~Addition(void); +}; + +/**************************************************/ +//! Multiplication block +/*! Multiplies all input values and outputs the result + * \todo_later Implement constant inputs (like in DSP_Addition) + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real or complex valued) + * -# "out.re" (real component)\n + * "out.im" (imag component if exists) + * - Input: + * -# "in1", "in2", ... - real/complex input (first are real valued inputs) + * -# "real_in1", "real_in2", ... - real inputs + * -# "cplx_in1", "cplx_in2", ... - complex inputs + * -# "cplx_in1.re", ... - real part of complex input + * -# "cplx_in1.im", ... - imaginary part of complex input + * -# "in1.re", "in1.im", ... - real/complex part of the input + * (sequence as for "in1", "in2", ...) + * . + * For block has one real input and two complex inputs + * we will have following predefined names: "real_in1", + * "cplx_in1", "cplx_in2" and "cplx_in1.re", "cplx_in1.im", + * "cplx_in2.re", "cplx_in2.im". + * + */ +class DSP::u::Multiplication : public DSP::Block +{ + private: + DSP::Float_ptr State; + DSP::Float State_Re, State_Im; +// DSP::Float temp_re; + + //! Recalculates initial value when constant input is set for this block + void RecalculateInitials(void); + + static void InputExecute(INPUT_EXECUTE_ARGS); + + public: + Multiplication(unsigned int NoOfRealInputs_in=2, + unsigned int NoOfComplexInputs_in=0); //numbers of inputs + ~Multiplication(void); +}; + +/**************************************************/ +//! Real multiplication block +/*! Multiplies all input values and outputs the result + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real valued) + * - Input: + * -# "real_in1", "real_in2", ... - real inputs + * -# "in1" == "real_in1", ... + * . + * . + * + * \note This block supports constant inputs (see DSP::Block::SetConstInput). + */ +class DSP::u::RealMultiplication : public DSP::Block +{ + private: + DSP::Float State; + DSP::Float RealInitialValue; + + //! Recalculates initial value when constant input is set for this block + void RecalculateInitials(void); + + static void InputExecute(INPUT_EXECUTE_ARGS); + + public: + RealMultiplication(unsigned int NoOfRealInputs_in=2U); //numbers of inputs + ~RealMultiplication(void); +}; + +/**************************************************/ +//! Decimator without antialias filter +/*! Inputs and Outputs names: + * - Output: + * -# "out1", "out2", ... (real valued) + * - Input: + * -# "in1", "in2", ... (real valued) + * + * \note It seems that decimation blocks do not need to + * be registered to the output clock, they just should know + * the output clock for error detection purpose. THIS MUST BE SORTED OUT. + */ +class DSP::u::RawDecimator : public DSP::Block, public DSP::Source +{ + private: + int M; + bool IsReady; + int InnerCounter; + DSP::Float *State; + + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + static void InputExecute(INPUT_EXECUTE_ARGS); + + public: + /*! \todo_later OutputClocks should be updated for each output + * not only first + */ + RawDecimator(DSP::Clock_ptr ParentClock, unsigned int M_in=2, unsigned int InputsNo=1); + ~RawDecimator(void); +}; + +//! Time expansion block: zeroinserter (+ hold) +/*! Inputs and Outputs names: + * - Output: + * -# "out" (real valued) + * - Input: + * -# "in" (real valued) + * + * \warning ParentClock is the clock with which works input not output. + * Output's clock works L times faster. To get output's clock use + * DSP::Component::GetOutputClock. + * + * \todo Complex or multivalued input/output. + */ +class DSP::u::Zeroinserter : public DSP::Block, public DSP::Source +{ + private: + unsigned int L; + bool IsInputReady, IsReady; + unsigned int InnerCounter; + DSP::Float tempInput_re, tempInput_im, State_re, State_im; + + bool IsHold; + + //!Execution as a source block + static bool OutputExecute_real(OUTPUT_EXECUTE_ARGS); + static bool OutputExecute_cplx(OUTPUT_EXECUTE_ARGS); + //!Execution as an processing block + static void InputExecute_real(INPUT_EXECUTE_ARGS); + static void InputExecute_cplx(INPUT_EXECUTE_ARGS); + + void Init(bool IsInputComplex, DSP::Clock_ptr ParentClock, unsigned int L_in, bool Hold); +public: + //if Hold == true, holds input value instead of inserting zeros + Zeroinserter(DSP::Clock_ptr ParentClock, unsigned int L_in=2, bool Hold=false); + Zeroinserter(bool IsInputComplex, DSP::Clock_ptr ParentClock, unsigned int L_in=2, bool Hold=false); + ~Zeroinserter(void); +}; + +// ***************************************************** // +//! Generates constant value +/*! + * Inputs and Outputs names: + * - Output: + * -# "out" (real, complex or multivalued valued) + * -# "out.re" (real component)\n + * "out.im" (imag component) + * -# "out1", "out2", ... (real or complex) + * -# "out1.re", "out2.re", ... (real part) + * -# "out1.im", "out2.im", ... (complex part) + * - Input: none + */ +class DSP::u::Const : public DSP::Source +{ + private: + DSP::Float const_val; + DSP::Float_ptr const_state; + + static bool OutputExecute_one(OUTPUT_EXECUTE_ARGS); + static bool OutputExecute_many(OUTPUT_EXECUTE_ARGS); + + public: + Const(DSP::Clock_ptr ParentClock, + DSP::Float value); + Const(DSP::Clock_ptr ParentClock, + DSP::Float value_re, DSP::Float value_im); + Const(DSP::Clock_ptr ParentClock, + DSP::Complex value); + Const(DSP::Clock_ptr ParentClock, + unsigned int NoOfInputs_in, DSP::Float_ptr values); + Const(DSP::Clock_ptr ParentClock, + unsigned int NoOfInputs_in, DSP::Complex_ptr values); + ~Const(void); +}; + +// ***************************************************** // +//! Generates pulse train +/*! + * -# N0 > N1: + * y[n]=A*exp(alfa*n)*cos(omega*n+phase)*(u[n-N0]-u[n-N1]) + * -# N0 <= N1: + * y[n]=A*exp(alfa*n)*cos(omega*n+phase)*u[n-N0] + * -# if period > 0 -> n = (n+1) \% period; + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real or complex valued) + * -# "out.re" (real component)\n + * "out.im" (imag component) + * - Input: none + */ +class DSP::u::COSpulse : public DSP::Source +{ + private: + DSP::Float A; + DSP::Float alfa; + DSP::Float omega, phase; + unsigned long N0, N1; + unsigned long period; + + unsigned long n; + + + //! Initiates inner variables + /*! Only for use with constructor + */ + void Init(DSP::Float A_in, DSP::Float alfa_in, + DSP::Float omega_in, DSP::Float phase_in, + unsigned long N0_in, unsigned long N1_in, + unsigned long period_in, + DSP::Clock_ptr ParentClock); + + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + public: + COSpulse(DSP::Clock_ptr ParentClock, + DSP::Float A_in, DSP::Float alfa_in=0.0, + DSP::Float omega_in=0.0, DSP::Float phase_in=0.0, + unsigned long N0_in=0, unsigned long N1_in=0, + unsigned long period_in=0); + COSpulse(DSP::Clock_ptr ParentClock, + bool IsComplex, DSP::Float A_in, DSP::Float alfa_in=0.0, + DSP::Float omega_in=0.0, DSP::Float phase_in=0.0, + unsigned long N0_in=0, unsigned long N1_in=0, + unsigned long period_in=0); + ~COSpulse(void); + + //! changes amplitude parameter + void SetAmplitude(DSP::Float new_amplitude); + //! Changes angular frequency + void SetAngularFrequency(DSP::Float omega_in); + //! Changes pulse length in samples + void SetPulseLength(int pulse_length); + //! Changes pulse train period in samples + void SetPulsePeriod(int pulse_period); +}; + +// ***************************************************** // +//! Generates uniform noise +/*! + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real or complex valued) + * -# "out.re" (real component)\n + * "out.im" (imag component) + * - Input: none + */ +class DSP::u::Rand : public DSP::Source, public DSP::Randomization +{ + private: + + + //! Initiates random generator + void Init(DSP::Clock_ptr ParentClock); + + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + public: + Rand(DSP::Clock_ptr ParentClock); + Rand(DSP::Clock_ptr ParentClock, + bool IsComplex); + ~Rand(void); +}; + +// ***************************************************** // +//! Generates random binary streams. +/*! Output value can be only L_value_in or U_value_in. + * Default: 0.0 and 1.0. + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real valued) + * - Input: none + */ +class DSP::u::BinRand : public DSP::Source, public DSP::Randomization +{ + private: + DSP::Float L_value; //! value corresponding to binary 0 + DSP::Float U_value; //! value corresponding to binary 1 + + //! Initiates random generator + void Init(DSP::Clock_ptr ParentClock, + DSP::Float L_value_in = 0.0, DSP::Float U_value_in = 1.0); + + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + public: + BinRand(DSP::Clock_ptr ParentClock, + DSP::Float L_value_in = 0.0, DSP::Float U_value_in = 1.0); + ~BinRand(void); +}; + +// ***************************************************** // +//! Generates LFSR binary streams. +/*! LFSR - linear feedback shift register. + * + * \todo test with register lengths >= 64 + * + * \todo_later <b>12.06.2008</b> For random initial state, output will be m-sequence + * after register length cycles. Consider outputing modulo 2 sum of + * taps instead of LSB of the register. + * + * \note Output value can be only L_value_in or U_value_in. + * Default: 0.0 and 1.0. + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real valued) + * - Input: none + * + * \note division by ULL_MSB can be changed into binary shift >> + * ! check if its value is correct (if it should not be larger). + */ +class DSP::u::LFSR : public DSP::Source, public DSP::Randomization +{ + private: + DSP::Float L_value; //! value corresponding to binary 0 + DSP::Float U_value; //! value corresponding to binary 1 + unsigned int reg_len; //! register length + unsigned int taps_no; //! number of feedback taps + unsigned int *taps; //! feedback taps indexes - 1 (index in buffer) + unsigned int buffer_size; // buffer size in ULL ints + unsigned long long int* buffer; //! buffer with internal register state + unsigned long long int buffer_MSB_mask; //! mask for MSB bit (the most left hand bit) + // LSB bit - the most right hand bit - mask == 0x0000..001 + unsigned long long int ULL_MSB; //! mask for MSB bit (the most right hand bit of unsigned long long int) + + //! Initiates shift register + void Init(DSP::Clock_ptr ParentClock, unsigned int reg_length, + unsigned int no_of_taps, unsigned int *taps_idx, + bool *state = NULL, + DSP::Float L_value_in = 0.0, DSP::Float U_value_in = 1.0); + + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + public: + /*! - reg_length - register length + * - no_of_taps - number of feedback taps + * - taps_idx - feedback taps indexes (1 .. reg_len) + * - state - initial register state (reg_len elements) + * . + * + * \note if state == NULL register will be initiated with + * none zero random sequence. + */ + LFSR(DSP::Clock_ptr ParentClock, unsigned int reg_length, + unsigned int no_of_taps, unsigned int *taps_idx, + bool *state = NULL, + DSP::Float L_value_in = 0.0, DSP::Float U_value_in = 1.0); + ~LFSR(void); +}; + +// ***************************************************** // +//! Tests LFSR binary streams. +/*! Tests LFSR - linear feedback shift register. + * + * \todo test with register lengths >= 64 + * + * \note Input value must be only L_value_in or U_value_in. + * Default: 0.0 and 1.0. + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real valued) + * - Input: + * -# "in" (real valued) + * + * \todo change division by ULL_MSB into binary shift >> + * ! check if it is correct value (if it should not be larger). + */ +class DSP::u::LFSR_tester : public DSP::Block, public DSP::Randomization +{ + private: + DSP::Float L_value; //! value corresponding to binary 0 + DSP::Float U_value; //! value corresponding to binary 1 + unsigned int reg_len; //! register length + unsigned int taps_no; //! number of feedback taps + unsigned int *taps; //! feedback taps indexes - 1 (index in buffer) + unsigned int buffer_size; // buffer size in ULL ints + unsigned long long int* buffer; //! buffer with internal register state + unsigned long long int ULL_MSB; //! mask for MSB bit (the most right hand bit of unsigned long long int) + + unsigned long long int buffer_MSB_mask; //! mask for MSB bit (the most left hand bit) + // LSB bit - the most right hand bit - mask == 0x0000..001 + + //! Initiates taps mask + void Init(unsigned int reg_length, unsigned int no_of_taps, unsigned int *taps_idx, + DSP::Float L_value_in = 0.0, DSP::Float U_value_in = 1.0); + + static void InputExecute(INPUT_EXECUTE_ARGS); + + public: + /*! - reg_length - register length + * - no_of_taps - number of feedback taps + * - taps_idx - feedback taps indexes (1 .. reg_len) + * - state - initial register state (reg_len elements) + * . + * + * \note if state == NULL register will be initiated with + * none zero random sequence. + */ + LFSR_tester(unsigned int reg_length, unsigned int no_of_taps, unsigned int *taps_idx, + DSP::Float L_value_in = 0.0, DSP::Float U_value_in = 1.0); + ~LFSR_tester(void); +}; + +// ***************************************************** // +//! Generates real/complex cosinusoid on the basis of DDS +/*! Uses phase acumulated modulo pi, thus can work forever + * \f[ + x[n]=A \cdot \cos(\sum_{n=0}^{+\infty}{\omega[n]+\varphi[n]}) + \f] + * + * Inputs and Outputs names: + * - Constant parameters version: + * - Output: + * -# "out" (real or complex valued) + * -# "out.re" (real component)\n + * "out.im" (imag component if exists) + * - Input: none + * - Runtime changeable parameters version: + * - Output: + * -# "out" (real or complex valued) + * -# "out.re" (real component)\n + * "out.im" (imag component if exists) + * - Input: + * -# "ampl" - cosinusoid amplitude + * -# "puls" - cosinusoid angular frequency + * -# "phase" - cosinusoid initial phase + * + */ +class DSP::u::DDScos : public DSP::Block, public DSP::Source +{ + private: + //! cosinusoid amplitude + DSP::Float A; + //! initial phase divided by DSP::M_PIx2 + DSP::Float phase; + //! cosinusoid normalized frequency (angular frequency divided by DSP::M_PIx2) + DSP::Float frequency; + + //! True if DDS generator parameters are ready (constant or read from inputs in current cycle) + bool InputParamsReady; +// //! Number of inputs read in current cycle +// int NoOfInputsRead; + + //! Cosinusoid instantaneous phase divided by DSP::M_PIx2 + /*! Strictly speaking it's just cumulated instantaneous frequency + * so it doesn't include initial phase (which in fact might be + * changing in time too) + */ + DSP::Float CurrentPhase; + + //! Initiation - only to be used in constructor + /*! frequency is given in [rad/cycle] + * phase is given in [rad] + */ + void Init(DSP::Float A_in, + DSP::Float frequency_in, DSP::Float phase_in, + DSP::Clock_ptr ParentClock); + + //! Recalculates initial values + void RecalculateInitials(void); + +// // ! Source execution function +// static bool OutputExecute(DSP::Source_ptr source, DSP::Clock_ptr clock=NULL); + //! Source execution function: real output / no inputs + static bool OutputExecute_real_no_inputs(OUTPUT_EXECUTE_ARGS); + //! Source execution function: complex output / no inputs + static bool OutputExecute_complex_no_inputs(OUTPUT_EXECUTE_ARGS); + //! Source execution function: real output & inputs + static bool OutputExecute_real(OUTPUT_EXECUTE_ARGS); + //! Source execution function: complex output & inputs + static bool OutputExecute_complex(OUTPUT_EXECUTE_ARGS); + //! Processing block execution function + /*! This function provides input parameters + * reception and processing + */ + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + //! DDS cosinusoid generator with constant parameters and real output + /*! Parameters are defined at block definition (creation) time. + * + * Frequency is given in [rad/cycle], + * phase is given in [rad] + */ + DDScos(DSP::Clock_ptr ParentClock, + DSP::Float A_in, + DSP::Float frequency_in=0.0, + DSP::Float phase_in=0.0); + //! DDS cosinusoid generator with constant parameters and real or complex output + /*! Parameters are defined at block definition (creation) time + * + * Frequency is given in [rad/cycle], + * phase is given in [rad] + */ + DDScos(DSP::Clock_ptr ParentClock, + bool IsComplex, + DSP::Float A_in, + DSP::Float frequency_in=0.0, + DSP::Float phase_in=0.0); + + //! DDS cosinusoid generator with runtime changeable parameters read from inputs and real output + /*! Parameters are read from inputs at runtime + * - input no 0 : cosinusoid amplitude + * - input no 1 : cosinusoid angular frequency + * - input no 2 : cosinusoid initial phase + * + * Frequency input should be given in [rad/cycle], + * phase input should be given in [rad] + * + * Inputs: Amplitude, angular frequency, initial phase + */ + DDScos(DSP::Clock_ptr ParentClock); + + //! DDS cosinusoid generator with runtime changeable parameters read from inputs and real or complex output + /*! Parameters are read from inputs at runtime + * - input no 0 : cosinusoid amplitude + * - input no 1 : cosinusoid angular frequency + * - input no 2 : cosinusoid initial phase + * + * Frequency input should be given in [rad/cycle] , + * phase input should be given in [rad] + * + * Inputs: Amplitude, angular frequency, initial phase + */ + DDScos(DSP::Clock_ptr ParentClock, bool IsComplex); + + ~DDScos(void); + + //! Changes angular frequency (if not associated with input) + void SetAngularFrequency(DSP::Float omega); + //! Changes amplitude (if not associated with input) + void SetAmplitude(DSP::Float amplitude); + DSP::Float GetFrequency(DSP::Float Fp) + {return frequency*Fp;} +}; + +/**************************************************/ +//! FIR filter implementation +/*! N_in - impulse response length (number of samples in h_in)\n + * h_in - impulse response samples + * n0 - index of the first sample to take + * M - get samples of impulse response decimated by M\n + * (extraction of polyphase filters, M > 1)\n + * Take samples: n0, n0+M, ... < N_in + * L - delay between consecutive filter taps. Used to implement shaping filters in I-FIR. + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real or complex valued) + * -# "out.re" (real component)\n + * "out.im" (imag component if exists) + * - Input: + * -# "in" (real or complex valued) + * -# "in.re" (real component)\n + * "in.im" (imag component if exists) + */ +class DSP::u::FIR : public DSP::Block +{ + private: + long N; + //! size of state buffer part to move in shaping filter implementation + long int memmove_size; + //! memory cell size in shaping filter implementation + int L_step; + + // if h == NULL, coefficients are complex + DSP::Float_vector h; + DSP::Complex_vector hC; + DSP::Float_vector State; + DSP::Complex in_value; + + void Init(bool IsInputComplex, bool AreCoeficientsComplex, + unsigned long N_in, const void *h_in, int n0, int M, int L); + + static void InputExecute_RI_RH1(INPUT_EXECUTE_ARGS); + static void InputExecute_RI_RH(INPUT_EXECUTE_ARGS); + static void InputExecute_RI_CH1(INPUT_EXECUTE_ARGS); + static void InputExecute_RI_CH(INPUT_EXECUTE_ARGS); + static void InputExecute_CI_RH1(INPUT_EXECUTE_ARGS); + static void InputExecute_CI_RH(INPUT_EXECUTE_ARGS); + static void InputExecute_CI_CH1(INPUT_EXECUTE_ARGS); + static void InputExecute_CI_CH(INPUT_EXECUTE_ARGS); + + static void InputExecute_RI_RH_L(INPUT_EXECUTE_ARGS); + + //static void InputExecute(INPUT_EXECUTE_ARGS); + public: + FIR(const DSP::Float_vector &h_in, int n0 = 0, int M = 1, int L = 1); + FIR(const DSP::Complex_vector &h_in, int n0 = 0, int M = 1, int L = 1); + + FIR(bool IsInputComplex, const DSP::Float_vector &h_in, int n0 = 0, int M = 1, int L = 1); + FIR(bool IsInputComplex, const DSP::Complex_vector &h_in, int n0 = 0, int M = 1, int L = 1); + ~FIR(void); +}; + +/**************************************************/ +//! IIR filter implementation +/*! Na_in - number of feedback coefficients + * a_in - feedback coefficients\n + * Nb_in - number of feedforward coefficients (if it's 1 or not specified + * all-pole IIR filter is created)\n + * b_in - feedforward coefficients (if it's NULL or not specified + * all-pole IIR filter is created) + * + * \note a_in and b_in coefficients are coppied to internal vectors + * thus user can free them as soon as the object is constructed. + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real or complex valued) + * -# "out.re" (real component)\n + * "out.im" (imag component if exists) + * - Input: + * -# "in" (real or complex valued) + * -# "in.re" (real component)\n + * "in.im" (imag component if exists) + */ +class DSP::u::IIR : public DSP::Block +{ + private: + long FilterOrder; +// int Na, Nb; + + // bool AreCoeficientsComplex; If a == NULL, coeficients are complex + DSP::Float_vector a, b; + DSP::Complex_vector aC, bC; + + DSP::Float_vector State; + DSP::Complex in_value; + + template <typename T> + void Init(bool IsInputComplex, bool AreCoeficientsComplex, T &a_in, T &b_in); + + static void InputExecute_real_coefs_cplx_input_zero_order(INPUT_EXECUTE_ARGS); + static void InputExecute_real_coefs_real_input_zero_order(INPUT_EXECUTE_ARGS); + static void InputExecute_cplx_coefs_cplx_input_zero_order(INPUT_EXECUTE_ARGS); + static void InputExecute_cplx_coefs_real_input_zero_order(INPUT_EXECUTE_ARGS); + + static void InputExecute_real_coefs_cplx_input(INPUT_EXECUTE_ARGS); + static void InputExecute_real_coefs_real_input(INPUT_EXECUTE_ARGS); + static void InputExecute_cplx_coefs_cplx_input(INPUT_EXECUTE_ARGS); + static void InputExecute_cplx_coefs_real_input(INPUT_EXECUTE_ARGS); + + public: + //! Allows for filter coefficients change. + /*! Sets new set of real valued coefficients. + * + * \note This version can be called only if + * real valued coefficients where used in + * block constructor. + * + * \note Number of coefficients must be identical to + * that set in block constructor. If filter order must be + * lowered then a_in or b_in vectors must be padded at the end + * with zeroes. + */ + bool SetCoefs(DSP::Float_vector &a_in, DSP::Float_vector &b_in); + //! Allows for filter coefficients change. + /*! Sets new set of complex valued coefficients. + * + * \note This version can be called only if + * complex valued coefficients where used in + * block constructor. + * + * \note Number of coefficients must be identical to + * that set in block constructor. If filter order must be + * lowered then a_in or b_in vectors must be padded at the end + * with zeroes. + */ + bool SetCoefs(DSP::Complex_vector &a_in, DSP::Complex_vector &b_in); + + //! DSP::Float_vector &b_in = {1} + IIR(DSP::Float_vector &a_in); + IIR(DSP::Float_vector &a_in, DSP::Float_vector &b_in); + //! DSP::Float_vector &b_in = {1} + IIR(bool IsInputComplex, DSP::Float_vector &a_in); + IIR(bool IsInputComplex, DSP::Float_vector &a_in, DSP::Float_vector &b_in); + + //! DSP::Float_vector &b_in = {1} + IIR(DSP::Complex_vector &a_in); + IIR(DSP::Complex_vector &a_in, DSP::Complex_vector &b_in); + //! DSP::Float_vector &b_in = {1} + IIR(bool IsInputComplex, DSP::Complex_vector &a_in); + IIR(bool IsInputComplex, DSP::Complex_vector &a_in, DSP::Complex_vector &b_in); + + ~IIR(void); +}; + +/**************************************************/ +//! Differator - first order backward difference operator +/*! + * Inputs and Outputs names: + * - Output: + * -# "out1", "out2", ... (real or complex valued) + * -# "out1.re", "out2.re", ... - real component\n + * "out1.im", "out2.im", ... - imag component if exists + * -# "out" == "out1" (real or complex valued) + * -# "out.re" == "out1.re" - real component\n + * "out.im" == "out1.im" - imag component if exists + * - Input: + * -# "in1", "in2", ... (real or complex valued) + * -# "in1.re", "in2.re", ... - real component\n + * "in1.im", "in2.im", ... - imag component if exists + * -# "in" == "in1" (real or complex valued) + * -# "in.re" == "in1.re" - real component\n + * "in.im" == "in1.im" - imag component if exists + */ +class DSP::u::Differator : public DSP::Block +{ + private: + std::vector <DSP::Float> State; + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + //! Setting up internal state + void SetInitialState(const DSP::Float_vector &State_init); + void SetInitialState(DSP::Float State_init); + void SetInitialState(DSP::Float State_init_re, DSP::Float State_init_im); + void SetInitialState(DSP::Complex State_init); + + Differator(int NoOfInputs_in, bool IsInputComplex=false); + ~Differator(void); +}; + +/**************************************************/ +//! Accumulator - first order operator +/*! + * Inputs and Outputs names: + * - Output: + * -# "out1", "out2", ... (real or complex valued) + * -# "out1.re", "out2.re", ... - real component\n + * "out1.im", "out2.im", ... - imag component if exists + * -# "out" == "out1" (real or complex valued) + * -# "out.re" == "out1.re" - real component\n + * "out.im" == "out1.im" - imag component if exists + * - Input: + * -# "in1", "in2", ... (real or complex valued) + * -# "in1.re", "in2.re", ... - real component\n + * "in1.im", "in2.im", ... - imag component if exists + * -# "in" == "in1" (real or complex valued) + * -# "in.re" == "in1.re" - real component\n + * "in.im" == "in1.im" - imag component if exists + */ +class DSP::u::Accumulator : public DSP::Block +{ + private: + DSP::Float lambda, one_minus_lambda; + DSP::Float_vector State; + + void Init(int NoOfInputs_in, DSP::Float lambda_in = 0.5, bool IsInputComplex=false); + + static void InputExecute_classic(INPUT_EXECUTE_ARGS); + static void InputExecute_leakage(INPUT_EXECUTE_ARGS); + public: + //! Setting up internal state + void SetInitialState(const DSP::Float_vector &State_init); + void SetInitialState(DSP::Float State_init); + void SetInitialState(DSP::Float State_init_re, DSP::Float State_init_im); + void SetInitialState(DSP::Complex State_init); + + //! Classic accumulator + Accumulator(int NoOfInputs_in = 1, bool IsInputComplex=false); + //! Accumulator with leakage + Accumulator(DSP::Float lambda_in, int NoOfInputs_in = 1, bool IsInputComplex=false); + ~Accumulator(void); +}; + +/**************************************************/ +//! Sampling rate conversion block +/*! N_in - impulse response length + * h_in - interpolation/decimation filter impulse response samples + * + * One state buffer working at input sampling rate and several polyphase filters + * - L filters \f$ h_i[n] = h[i+nL]\f$ where \f$i = 0 .. L-1\f$ + * - output samples are evaluated for every \f$M^{th}\f$ filter (modulo L) + * - if L > M for some input sample there will be no output sample + * - if L < M we need output samples buffer larger then for one sample, + * possibly for ceil(L/M) samples + * + * StateBuffer length = ceil(N_in/L) = floor((N_in+L-1)/L) (including current input sample)\n + * OuputBuffer length = ceil(L/M) = floor ((L+M-1)/M) + * + * <b> Implementation should be input driven </b>: + * this means: output samples should be evaluated when input + * sample is available, and stored in OutputBuffer + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real valued) + * - Input: + * -# "in" (real valued) + * + * + * \todo_later Implement version with complex interpolation filter impulse respose + */ +class DSP::u::SamplingRateConversion : public DSP::Block, public DSP::Source +{ + private: + //int N; + //! interpolation/decimation filter impulse response + DSP::Float_vector h_real; + DSP::Complex_vector h_cplx; + + unsigned int CurrentFilterIndex, dn; + unsigned int L, M; + + + //! Number of samples available in output buffer + unsigned int NoOfSamplesReady; + //! Buffer for the output samples + DSP::Float_vector OutputBuffer_real; + DSP::Complex_vector OutputBuffer_cplx; + + //! State buffer for polyphase filters + DSP::Float_vector StateBuffer_real; + DSP::Complex_vector StateBuffer_cplx; + + //! Variable for storing components of the input sample (in case of complex inputs) + DSP::Complex in_value; + + void Init(bool IsInputComplex, unsigned int L_in, unsigned int M_in, + const DSP::Float_vector &h_in, + DSP::Clock_ptr ParentClock); + void Init(bool IsInputComplex, unsigned int L_in, unsigned int M_in, + const DSP::Complex_vector &h_in, + DSP::Clock_ptr ParentClock); + + static void InputExecute_real_in_real_h(INPUT_EXECUTE_ARGS); + static void InputExecute_cplx_in_real_h(INPUT_EXECUTE_ARGS); + static void InputExecute_real_in_cplx_h(INPUT_EXECUTE_ARGS); + static void InputExecute_cplx_in_cplx_h(INPUT_EXECUTE_ARGS); + static bool OutputExecute_real_out(OUTPUT_EXECUTE_ARGS); + static bool OutputExecute_cplx_out(OUTPUT_EXECUTE_ARGS); + + public: + //! Variant assumming IsInputComplex = false + SamplingRateConversion(DSP::Clock_ptr ParentClock, unsigned int L_in, unsigned int M_in, + const DSP::Float_vector &h_in); + //! Variant assumming IsInputComplex = false + SamplingRateConversion(DSP::Clock_ptr ParentClock, unsigned int L_in, unsigned int M_in, + const DSP::Complex_vector &h_in); + SamplingRateConversion(bool IsInputComplex, + DSP::Clock_ptr ParentClock, unsigned int L_in, unsigned int M_in, + const DSP::Float_vector &h_in); + SamplingRateConversion(bool IsInputComplex, + DSP::Clock_ptr ParentClock, unsigned int L_in, unsigned int M_in, + const DSP::Complex_vector &h_in); + ~SamplingRateConversion(void); +}; + +/**************************************************/ +//! Maximum selector. Outputs: (1) maximum value (2) number of input where maximum is observed +/*! + * Inputs and Outputs names: + * - Output: + * -# "out" maximum value (real valued) + * -# "max" == "out" + * -# "ind" - input index where the maximum value has been observed. + * This is the first input with such value. Indeks value starts + * from 1. + * - Input: + * -# "in1", "in2", ... - real i-th input + */ +class DSP::u::Maximum : public DSP::Block +{ + DSP::Float temp_max; + unsigned int max_ind; + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + Maximum(unsigned int NumberOfInputs=2); + ~Maximum(void); +}; + +// ***************************************************** // +//! Outputs selected input (given by the number) +/*! + * Inputs and Outputs names: + * - Output: + * -# "out" value of the selected input (real or complex valued) + * -# "out.re" - real component + * -# "out.im" - imag component (if exists) + * - Input: + * -# "ind" - indeks of selected input (result of floor() from the given value). + * By default indexes start from 1. Can be changed by setting IndexOffset. + * -# "in1", "in2", ... - real or complex i-th input + * -# "in1.re", "in2.re", ... - real component of the i-th input + * -# "in1.im", "in2.im", ... - imag component of the i-th input + */ +class DSP::u::Selector : public DSP::Block +{ + unsigned int in_values_len; + DSP::Complex_ptr in_values; + unsigned int index; + int index_offset; + private: + void Init(bool AreInputsComplex, + unsigned int NumberOfInputs, + int IndexOffset); + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + Selector(unsigned int NumberOfInputs=2u, + int IndexOffset=1); + Selector(bool AreInputsComplex, unsigned int NumberOfInputs=2U, + int IndexOffset=1); + ~Selector(void); +}; + +/**************************************************/ +//! Block calculating absolute value of real or complex sample +/*! + * Inputs and Outputs names: + * - Output: + * -# "out" (real valued) + * - Input: + * -# "in" - real or complex input + * -# "in.re" - real component + * "in.im" - imag component (if exists) + */ +class DSP::u::ABS : public DSP::Block +{ + private: + DSP::Complex in_value; + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + ABS(bool IsInputComplex=true); + ~ABS(void); +}; + +/**************************************************/ +//! Block calculating complex conjugation of complex sample +/*! + * Inputs and Outputs names: + * - Output: + * -# "out" - complex output + * -# "out.re" - real component /n + * "out.im" - imag component + * - Input: + * -# "in" - complex input + * -# "in.re" - real component /n + * "in.im" - imag component + */ +class DSP::u::Conjugation : public DSP::Block +{ + private: + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + Conjugation(void); + ~Conjugation(void); +}; + +/**************************************************/ +//! Block calculating the phase of a complex sample +/*! + * Inputs and Outputs names: + * - Output: + * -# "out" (real valued) + * - Input: + * -# "in" - complex input + * -# "in.re" - real component + * "in.im" - imag component + */ +class DSP::u::Angle : public DSP::Block +{ + private: + DSP::Complex in_value; + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + Angle(void); + ~Angle(void); +}; + +/**************************************************/ +//! CMPO - complex mutual power operator +/*! + * + * \f$ b[n]=u[n] \cdot u^*[n-1] \f$ + * + * Inputs and Outputs names: + * - Output: + * -# "out" (complex valued) + * -# "out.re" - real component\n + * "out.im" - imag component + * - Input: + * -# "in" - complex input + * -# "in.re" - real component\n + * "in.im" - imag component + */ +class DSP::u::CMPO : public DSP::Block +{ + private: + DSP::Complex last_value; + DSP::Complex in_value; + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + CMPO(void); + ~CMPO(void); +}; + +/**************************************************/ +//! CCPC - cartesian coordinated to polar coordinates converter +/*! + * + * \f$ p[n]=|u[n]| + j \cdot \arg(u[n]) \f$ + * + * Inputs and Outputs names: + * - Output: + * -# "out" (complex valued) + * -# "out.abs" - absolute value (real component)\n + * "out.arg" - phase (imag component) + * -# "out.re" == "out.abs"\n + * "out.im" == "out.arg + * - Input: + * -# "in" - complex input + * -# "in.re" - real component\n + * "in.im" - imag component + */ +class DSP::u::CCPC : public DSP::Block +{ + private: + DSP::Complex in_value; + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + CCPC(void); + ~CCPC(void); +}; + +/**************************************************/ +//! PCCC - polar coordinated to cartesian coordinates converter +/*! + * + * \f$ u[n]=a[n] \cdot e^{j \cdot \phi[n]} \f$ + * + * Inputs and Outputs names: + * - Output: + * -# "out" (complex valued) + * -# "out.re" - real component\n + * "out.im" - imag component + * - Input: + * -# "in" - complex input + * -# "in.abs" - absolute value (real component)\n + * "in.arg" - phase (imag component) + * -# "in.re" == "in.abs"\n + * "in.im" == "in.arg + */ +class DSP::u::PCCC : public DSP::Block +{ + private: + DSP::Float in_value_abs; + DSP::Float in_value_phase; + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + PCCC(void); + ~PCCC(void); +}; + +/**************************************************/ +//! User defined function block +/*! + * + * Inputs and Outputs names: + * - Output: + * -# "out" - all output lines + * -# "out1", "out2" - i-th output (real valued) + * . + * Output "out1" -> OutputSamples[0]\n + * Output "out2" -> OutputSamples[1]\n + * ... + * - Input: + * -# "in" - all input lines + * -# "in1", "in2" - i-th input (real valued) + * . + * Input "in1" -> InputSamples[0]\n + * Input "in2" -> InputSamples[1]\n + * ... + * + * \warning Inputs and Output interpretation depends on the user. + * + * Callback funtion: + * void func(int NoOfInputs, DSP::Float_ptr InputSamples, + * int NoOfOutputs, DSP::Float_ptr OutputSamples, + * DSP::void_ptr *UserDataPtr, int UserDefinedIdentifier) + * + * UserDataPtr - default value is NULL, in this variable user can store + * the pointer to his own data structure + * UserDefinedIdentifier - value specified in class constructor: CallbackIdentifier + * + * This callback function is in addtion to calls when input samples are + * to be processed, is called twice more times: + * -# call from block constructor with NoOfInputs = -1; + * this is when the user can initiate UserData structure + * -# call from block destructor with NoOfInputs = -2; + * this is when the user can free UserData structure + */ +class DSP::u::MyFunction : public DSP::Block +{ + private: + int UserCallbackID; + DSP::Callback_ptr UserFunction_ptr; + DSP::void_ptr UserData; + + DSP::Float_ptr InputData; + DSP::Float_ptr OutputData; + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + MyFunction(unsigned int NumberOfInputs, unsigned int NumberOfOutputs, + DSP::Callback_ptr func_ptr, int CallbackIdentifier=0); + ~MyFunction(void); +}; + +/**************************************************/ +//! Outputs some inputs samples on the basis of activation signal +/*! If the activation signal is > 0 then the input values are + * send to the output + * + * Output samples are processed when all input values (including activation + * signal) are ready. When State[0] > 0 then process outputs otherwise do nothing. + * + * State[0] - activation signal + * State[1-...] - input signals + * + * \note Output clock must be activated separetly with DSP::u::ClockTrigger + * + * Inputs and Outputs names: + * - Output: + * -# "out1", "out2", ... + * -# "out.re" == "out1", "out.im" == "out2" + * -# "out" == all output lines + * - Input: + * -# "in1", "in2", ... + * -# "in.re" == "in1", "in.im" == "in2" + * -# "in" == all output lines with the exception of "act" + * -# "act" activation signal <= exists only when ActivateOutputClock is <b>true</b> + * . + * . + */ +class DSP::u::SampleSelector : public DSP::Block, public DSP::Source, public DSP::Clock_trigger +{ + private: + DSP::Float_ptr State; + +// protected: +// void SetBlockInputClock(int InputNo, DSP::Clock_ptr InputClock); + public: + DSP::Clock_trigger_ptr Convert2ClockTrigger(void) + { return GetPointer2ClockTrigger(); }; + + //! SampleSelector constructor + /*! + * Parameters: + * - ParentClock - Clock with which inputs work. Required for syntax + * checking and clock activation. Might be NULL only if + * ActivateOutputClock is set to <b>false</b>. + * - OutputClock + * - output clock determines when the output samples are generated. + * - if ActivateOutputClock is <b>true</b> this is clock which will + * be activated for each sample selection. + * - <b>NULL</b> if undefined. This should be used only if + * output brach has no sources at all and ActivateOutputClock + * is set <b>false</b> + * - ActivateOutputClock + * - <b>true</b> if block have to work as DSP::u::ClockTriger + * activating output clock for each sample selection. + * - <b>false</b> if output clock is not defined or is activated + * by other block, e.g. with several DSP::u::SampleSelector blocks + * working synchronous. + * - NumberOfInputs - means number of inputs and equals number of outputs. + * + * \warning Activation signal input doesn't count to the NumberOfInputs. + * + */ + SampleSelector(DSP::Clock_ptr ParentClock, DSP::Clock_ptr OutputClock, + bool ActivateOutputClock, int NumberOfInputs=1); + //! SampleSelector backward compatibility constructor <b>[OBSOLETE]</b> + /*! \note This version is provided only for backward compatibility + * with DSP_lib version older than 0.07.003. + * OutputClock is assumed NULL and ActivateOutputClock is assumed false. + */ + SampleSelector(DSP::Clock_ptr ParentClock, int NumberOfInputs=1); + //! SampleSelector destructor + ~SampleSelector(void); + + //! true if all input samples in current cycle are ready + bool SamplesReady; + + //! Output samples are generated when "act" signal is in active state + static void InputExecute_without_source_output(INPUT_EXECUTE_ARGS); + //! Output samples are generated when OutputClock is active + static void InputExecute(INPUT_EXECUTE_ARGS); + //! InputExecute version which activates output clock. Output samples are generated when OutputClock is active. + static void InputExecute_with_Activation(INPUT_EXECUTE_ARGS); + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + void Notify(DSP::Clock_ptr clock); + private: + //! Block initiation procedure + /*! For use with block constructors + */ + void Init(DSP::Clock_ptr ParentClock, DSP::Clock_ptr OutputClock, + bool ActivateOutputClock, unsigned int NumberOfInputs); +}; + +//! Reads samples acording to one clocks' group and outputs acording to other clocks' group +/*! Generaly Input & Output clocks should have different output clocks\n + * Last sample seen on input is send to the output if required. + * Some samples can be lost, some might be repeated several times. + * + * \note In most cases you would rather use DSP::u::Zeroinserter with IsHold set to true. + * \note This block is an example of using notifications. + * \warning because Input & Output clocks are independent to some extend then + * time hazards can occur. + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real, complex or multivalued) + * -# "out.re" (real component)\n + * "out.im" (imag component if exists) + * -# "out1", "out2", "out3", ... + * - Input: + * -# "in" (real, complex or multivalued) + * -# "in.re" (real component)\n + * "in.im" (imag component if exists) + * -# "in1", "in2", "in3", ... + * . + * + * \todo <b>IMPORTANT</b> + * - issue warning when Input & Output have the same MasterClock + */ +class DSP::u::Hold : public DSP::Block, public DSP::Source +{ + private: + DSP::Float_ptr currentState; + DSP::Float_ptr newState; + /*! false if Input and Output clocks have the + * same MasterClock and Input is Expected in + * the given clock cycle. + */ + bool SamplesReady; + + /*! if IsHold == false the current_State will be filled with zeros + * after it was sent do outputs */ + bool IsHold; + + //! stores output clock in case we must stall it for some time + DSP::Clock *my_clock; + +// protected: +// void SetBlockInputClock(int InputNo, DSP::Clock_ptr InputClock); + + static void InputExecute(INPUT_EXECUTE_ARGS); + void Notify(DSP::Clock_ptr clock); + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + public: + + //! InputClock == NULL <- auto detection at connection time + /*! if UseZeros == true the output will be filled with zeros + * otherwise with last sample + */ + Hold(DSP::Clock_ptr InputClock, DSP::Clock_ptr OutputClock, bool UseZeros=false, unsigned int NumberOfInputs=1); + ~Hold(void); +}; + + +/**************************************************/ +//! Demultiplexer block (y1[n]=x[L*n], y2[n]=x[L*n+1], yL[n]=x[L*n+L-1]) +/*! Inputs and Outputs names: + * - Output: + * -# "out1", "out2", ... (real or complex valued) + * -# "out1.re", "out2.re", ... real components + * -# "out1.im", "out2.im", ... imaginary components (if they exist) + * -# "out" all output lines + * . + * - Input: + * -# "in" - (real or complex valued) + * -# "in.re" - real component + * -# "in.im" - imaginary component (if exist) + * . + */ +class DSP::u::Demultiplexer : public DSP::Block // , public DSP::Source +{ + private: + //! Number of the output where the current sample should be forwarded + int CurrentOutputNo; + DSP::Float State[2]; + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + Demultiplexer(bool IsComplex, unsigned int OutputsNo=2); + ~Demultiplexer(void); +}; + + +//! Multiplexer block (y[L*n]=x1[n], y[L*n+1]=x2[n], y[L*n+L-1]=xL[n]) +/*! Inputs and Outputs names: + * - Output: + * -# "out" - (real or complex valued) + * -# "out.re" - real component + * -# "out.im" - imaginary component (if exist) + * . + * - Input: + * -# "in1", "in2", ... (real or complex valued) + * -# "in1.re", "in2.re", ... real components + * -# "in1.im", "in2.im", ... imaginary components (if they exist) + * -# "in" all input lines + * . + * . + */ +class DSP::u::Multiplexer : public DSP::Block, public DSP::Source +{ + private: + //! Number of current the output sample + int CurrentOutputSampleNo; + DSP::Float_ptr State; + //! true if given state slot is ready + bool *StateReady; + + // //!Execution as a source block + // static bool OutputExecute(DSP::Source_ptr source, DSP::Clock_ptr clock=NULL); + //!Execution as a source block for real input + static bool OutputExecute_real(OUTPUT_EXECUTE_ARGS); + //!Execution as a source block for complex input + static bool OutputExecute_cplx(OUTPUT_EXECUTE_ARGS); + //!Execution as an processing block + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + Multiplexer(DSP::Clock_ptr ParentClock, bool IsComplex, unsigned int InputsNo=2); + ~Multiplexer(void); +}; + +/**************************************************/ +//! DCO - digitaly controled oscilator +/*! + * + * Inputs and Outputs names: + * - Output: + * -# "out" (complex valued) + * -# "out.re" - real component\n + * "out.im" - imag component + * -# "freq" available only if output_current_frequency == <b>true</b> + * (instantaneous normalized frequency of the oscillator) + * . + * - Input: + * -# "in.freq_err" - angular frequency error correction input + * -# "in.phase_err" - phase error correction input + * . + */ +class DSP::u::DCO : public DSP::Block +{ + private: + DSP::Float fo; + DSP::Float freq_factor; + DSP::Float phase_factor; + //DSP::Float max_freq_deviation; + DSP::Float freq_dev_min, freq_dev_max; + + DSP::Float freq_memo, phase_memo; + + //temporary input variables + DSP::Float in_freq_err; + DSP::Float in_phase_err; + + //! DCO main routine + /*! + * \image html DCO_scheme.jpg + * + */ + static void InputExecute(INPUT_EXECUTE_ARGS); + DSP::Float current_frequ; + static void InputExecute_with_Freq(INPUT_EXECUTE_ARGS); + public: + DCO(DSP::Float wo //!initial normalized angular frequency of the oscilator [rad/Sa] + , DSP::Float d_wo //! maximum allowed frequency deviation (ignored if < 0.0) + , DSP::Float freq_alfa //! angular frequency error correction input scaling factor [rad/Sa] + , DSP::Float phase_alfa //! phase error correction input scaling factor [rad] + , bool output_current_frequency = false //! if true additional output with current frequency value is available + ); + ~DCO(void); + + //! returns current estimated signal frequency in Hz for given sampling frequency + DSP::Float GetFrequency(DSP::Float Fp); +}; + +/**************************************************/ +//! CrossSwitch - sends input signals stright or crossed to outputs +/*! + * \todo_later Implement multi-valued inputs/outputs + * + * Stright connection: in1 -> out1; in2 -> out2 + * + * Crossed connection: in1 -> out2; in2 -> out1 + * + * Inputs and Outputs names: + * - Output: + * -# "out1" (real or complex valued) + * -# "out1.re" - real component\n + * "out1.im" - imag component (if there is one) + * -# "out2" (real or complex valued) + * -# "out2.re" - real component\n + * "out2.im" - imag component (if there is one) + * - Input: + * -# "state" - 0 - stright connection, 1 - crossed connection + * -# "in1" (real or complex valued) + * -# "in1.re" - real component\n + * "in1.im" - imag component (if there is one) + * -# "in2" (real or complex valued) + * -# "in2.re" - real component\n + * "in2.im" - imag component (if there is one) + */ +class DSP::u::CrossSwitch : public DSP::Block +{ + private: + int state; //! ??? false if stright, true if crossed + int default_state; + + DSP::Float_ptr inputs; + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + //! if IsComplex is true inputs are complex + CrossSwitch(bool IsComplex = false); + ~CrossSwitch(void); +}; + +/**************************************************/ +//! ClockTrigger - activates given clock based on activation signal +/*! + * Inputs and Outputs names: + * - Output: + * - Input: + * -# "act" - activation signal + * - if NoOfCycles >= 1, input > 0.0 triggers clock for NoOfCycles, + * \note it is best to use activation signal with values from set {-1.0, +1.0} + * where +1.0 activates clock. + * - if NoOfCycles == -1, input > 0.0 triggers clock for + * (int)(input + 0.5) == round(input) cycles + * - input < 0.0 -> no activation + * - input = (0, 0.5) -> one cycle + * - input = [0.5, 1.5) -> two cycles + * - input = [1.5, 2.5) -> three cycles + * - ... + * . + * . + * . + * . + * \warning InputClock MUST be different from OutputClock + */ +class DSP::u::ClockTrigger : public DSP::Block, public DSP::Clock_trigger +{ + private: + static void InputExecute(INPUT_EXECUTE_ARGS); + static void InputExecute_multivalue(INPUT_EXECUTE_ARGS); + + public: + DSP::Clock_trigger_ptr Convert2ClockTrigger(void) + { return GetPointer2ClockTrigger(); }; + + /*! MasterClockIndex - index of MasterClock with which "act" signal works + * SignalActivatedClock - clock to trigger + * NoOfCycles - number of OutputClock cycles per clock activation + * - if (NoOfCycles == -1) - number of OutputClock cycles + * per clock activation is given by "act" signal + */ + ClockTrigger(DSP::Clock_ptr ParentClock, DSP::Clock_ptr SignalActivatedClock_in, int NoOfCycles_in = 1); + ~ClockTrigger(void); +}; + + + +/**************************************************/ +//! See through type copy block +/*! Simply copies input to output thus + * number of outputs is equal to + * number of inputs. + * + * This block has been designed to be used internaly in DSP::Macro + * + * \note This block is the abstract object. + * All connections are made directly + * between block's input and output components. + * + * \note This block can be freed + * after all connections are made. + * + * Inputs and Outputs names: + * - Output: + * -# "out" - all output lines + * . + * - Input: + * -# "in" - all input lines + * . + * + * The general idea for this block is to provide possibility + * to create names for input and outputs spaning + * through several different blocks. + * + * \note Other inputs and outputs must be defined by user. + */ +class DSP::u::Copy : public DSP::Block +{ + friend class DSP::Component; + friend class DSP::Macro; + + //friend bool DSP::_connect_class::splitconnect(const DSP::output &output, const DSP::input &input); + friend class _connect_class; + + private: + //! Raw output block reading function + bool GetOutput(unsigned int OutputNo, DSP::Component_ptr &output_block, unsigned int &output_block_InputNo); + + private: + //static void InputExecute(INPUT_EXECUTE_ARGS); + + //! DSP::u::Copy output info update + /*! DSP::u::Copy component's output with index OutputNo must be + * connected to block's input with index block_InputNo. + * + * DSP::u::Copy must store this info and use it to + * help DSP::Component::DSP::_connect_class::connect directly connect + * block which user connects through DSP::u::copy component. + * + * Returns false if input block is still unknown. + */ + bool SetCopyOutput(unsigned int OutputNo, DSP::Block_ptr block, unsigned int block_InputNo); + //! Returns block and its input number to which is connected given DSP::u::Copy block output + /*! If the requested data is no available function returns false and + * - output_block = NULL + * - output_block_InputNo = FO_NoInput + * . + */ + bool GetCopyOutput(unsigned int OutputNo, DSP::Block_ptr &output_block, unsigned int &output_block_InputNo); + //! DSP::u::Copy input info update + /*! DSP::u::Copy component's input with index InputNo must be + * connected to block's output with index block_OutputNo. + * + * DSP::u::Copy must store this info and use it to + * help DSP::Component::DSP::_connect_class::connect directly connect + * block which user connects through DSP::u::copy component. + * + * Returns false if output block is still unknown. + */ + bool SetCopyInput(unsigned int InputNo, DSP::Component_ptr block, unsigned int block_OutputNo); + //! Returns component and its output number connected to given DSP::u::Copy block input + /*! If the requested data is no available function returns false and + * - input_block = NULL + * - input_block_OutputNo = FO_NoOutput + * . + */ + bool GetCopyInput(unsigned int InputNo, DSP::Component_ptr &input_block, unsigned int &input_block_OutputNo); + + DSP::u::Copy_ptr Convert2Copy(void) + { return (DSP::u::Copy_ptr)this; }; + + DSP::Component_ptr *InputBlocks; //!one block pointer per one output + unsigned int *InputBlocks_OutputNo; //!Input number of the output block + + public: + Copy(unsigned int NoOfInputs_in); + ~Copy(void); +}; + + + +/**************************************************/ +//! Quantizer +/*! + * Inputs and Outputs names: + * - Output: + * -# "out" - real valued output + * - Input: + * -# "in" - real valued input + * . + * + * \todo implement version for mo�e quantization levels + */ +class DSP::u::Quantizer : public DSP::Block +{ + private: + //! number of bits - with sign bit + unsigned int B; + //! quantization thresholds + DSP::Float_vector thresholds; + //! values corresponding to quantization levels + DSP::Float_vector q_levels; + + DSP::Float output_val; + + static void InputExecute_1bit(INPUT_EXECUTE_ARGS); + public: + //! 1-bit quantizer + /*! - value <= threshold ==> returns L_value + * - value > threshold ==> returns U_value + * . + */ + Quantizer(DSP::Float threshold = 0.0, DSP::Float L_value = -1.0, DSP::Float U_value = +1.0); + //DSP::u::Quantizer(unsigned int B_in); + ~Quantizer(void); +}; + + +#endif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_modules2.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_modules2.h new file mode 100644 index 0000000000000000000000000000000000000000..f26afcb2dbfab22846efef93cac2667e3b9509ae --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_modules2.h @@ -0,0 +1,831 @@ +/*! \file DSP_modules2.h + * This is DSP engine components and sources definition module header file. + * + * \author Marek Blok + */ +#ifndef DSPmodules2H +#define DSPmodules2H + +//--------------------------------------------------------------------------- +#include <DSP_setup.h> +//--------------------------------------------------------------------------- +#include <DSP_types.h> +#include <DSP_misc.h> +#include <DSP_Fourier.h> +#include <DSP_modules.h> + +namespace DSP { + namespace u { + class AGC; + class BPSK_SNR_estimator; + class Farrow; + class FFT; + class DynamicCompressor; + class GardnerSampling; + class TimingErrorDetector; + class PSKencoder; + class PSKdecoder; + class Serial2Parallel; + class Parallel2Serial; + class SymbolMapper; + class SymbolDemapper; + } + + namespace e { + enum struct GardnerSamplingOptions : unsigned int; + inline DSP::e::GardnerSamplingOptions operator|(DSP::e::GardnerSamplingOptions __a, DSP::e::GardnerSamplingOptions __b); + inline DSP::e::GardnerSamplingOptions operator&(DSP::e::GardnerSamplingOptions __a, DSP::e::GardnerSamplingOptions __b); + } +} + +/**************************************************/ +//! AGC - automatic gain control +/*! + * + * Inputs and Outputs names: + * - Output: + * -# "out" (complex valued) + * -# "out.re" - real component\n + * "out.im" - imag component + * - Input: + * -# "in" (complex valued) + * -# "in.re" - real component\n + * "in.im" - imag component + */ +class DSP::u::AGC : public DSP::Block +{ + private: + DSP::Float alfa; + DSP::Float signal_power; + DSP::Float out_power; + + DSP::Complex input; + + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + AGC(DSP::Float alfa_in, //! forgeting factor + DSP::Float init_signal_power=1.0, //! initial value of the signal power + DSP::Float output_signal_power=1.0 //! output signal power + ); + ~AGC(void); + + //! returns current estimated signal power + DSP::Float GetPower(void); +}; + + +// ***************************************************** // +//! Signal to noise ratio estimation for BPSK modulation +/*! + * Inputs and Outputs names: + * - Output: + * -# "snr" - estimated SNR value + * - Input: + * -# "in" - complex valued signal + * -# "in.re" - real component + * -# "in.im" - imag component + */ +class DSP::u::BPSK_SNR_estimator : public DSP::Block +{ + private: + //! number of symbols used for current value estimation + int SegmentSize; + + //! buffer for real input values of the size SegmentSize + DSP::Float_vector RealBuffer; + //! current free slot RealBuffer index + int current_ind; + + //! Current values of real and imag symbol components + DSP::Float Input_Real, Input_Imag; + + //! Current value of the estimated SNR + DSP::Float EstimatedSNR; + + //! Processing block execution function + /*! This function provides input parameters + * reception and processing + */ + static void InputExecute(INPUT_EXECUTE_ARGS); + public: + //! DSP::u::BPSK_SNR_estimator constructor + /*! segment_size - number of symbols used for current value estimation, + */ + BPSK_SNR_estimator(int segment_size); + + ~BPSK_SNR_estimator(void); +}; + +namespace DSP { + namespace f { + //! SNR estimation for PSK modulation (BPSK & QPSK) based on complex symbol samples + /*! 1) buffer_size is in symbols + * 2) buffer contains 2*buffer_size floating point values (real & imag) + * + * \note Buffer content is preserved. + */ + void PSK_SNR_estimator(const int &buffer_size, const DSP::Float_vector &buffer, + DSP::Float &BPSK_SNR, DSP::Float &QPSK_SNR); + } +} + +/**************************************************/ +//! DynamicCompressor - changes input signal dynamic +/*! + * Inputs and Outputs names: + * - Output: + * -# "out" - real or complex output signal + * -# "out.re" - real part of output signal + * -# "out.im" - imaginary part of output signal (if it exists) + * - Input: + * -# "in" - real or complex input signal + * -# "in.re" - real part of input signal + * -# "in.im" - imaginary part of input signal (if it exists) + */ +class DSP::u::DynamicCompressor : public DSP::Block +{ + private: + DSP::Float_vector SamplesBuffer; + DSP::Float_vector PowerBuffer; //! Sample Energy per PowerBufferSize + unsigned int index; //! index of the current free entry in SamplesBuffer + unsigned int power_index; //! index of the current free entry in PowerBuffer + //output_index == index because the SampleBuffer is shorter then PowerBuffer + //unsigned int output_index; //! index of the output sample + + //! ??? BufferSize_in * (number of sample components) + /*! !!! it seems that OutputDelay * (number of sample components) would be enough + */ + unsigned int SamplesBufferSize; + unsigned int PowerBufferSize; //! BufferSize_in + + DSP::Complex temp_value; + DSP::Float factor_0, alfa; + DSP::Float CurrentPower; //! Current input signal power evaluated based on values in PowerBuffer + + static void InputExecute_no_delay_real(INPUT_EXECUTE_ARGS); + static void InputExecute_no_delay_complex(INPUT_EXECUTE_ARGS); + static void InputExecute_real(INPUT_EXECUTE_ARGS); + static void InputExecute_complex(INPUT_EXECUTE_ARGS); + public: + /*! DynamicCompressor constructor + * BufferSize - size (in samples) of the buffer used to estimate input signal power. + * a0 - compression factor, dynamic [dB] at output will be a0 times smaller than at input + * Po_dB - power reference point [dB]. If input power equals Po_dB then + * output power will also be Po_dB. + * IsInputComplex - indicates whether the input is real or complex. + * OutputDelay - delay (in samples) of the output signal. + * Default delay (OutputDelay = -1) is floor((BufferSize_in-1)/2). + * Any value in range from 0 to BufferSize_in-1 can be set. + */ + DynamicCompressor(int BufferSize_in, DSP::Float a0, DSP::Float Po_dB = 0.0, + bool IsInputComplex = false, int OutputDelay_in = -1); + ~DynamicCompressor(void); +}; + + +//! Farrow structure - gives output sample when output clock is activated +/*! \note Input & Output clocks can have different clocks. + * + * \warning because Input & Output clocks are independent to some extend then + * time hazards can occur. + * + * Inputs and Outputs names: + * - Output: + * -# "out" (real or complex) evaluated sample + * -# "out.re" (real component)\n + * "out.im" (imag component if exists) + * - Input: + * -# "in" (real or complex) input signal to be delayed + * -# "eps" (real) net delay to be implemented + * . + * + * "eps" input can have the same clock as "in" or "out". + * If "eps" has clock common with "out" notification + * function must be used for both clocks. Separate for "in" and "eps". + * + * \note For current implementation "eps" must have the same clock as "out" which can be the same as the clock for "in" + */ +class DSP::u::Farrow : public DSP::Block, public DSP::Source +{ + private: + //! length of implemented FSD filter + unsigned long N_FSD; + //! input signal buffer + /*! for real input table od DSP::Float /n + * for complex input table od DSP::Complex + * + * \note that most recent sample is the last sample in buffer + */ + std::vector<uint8_t> Buffer; + + //! Order of the Farrow structure + 1 (length of Farrow polynomials) + unsigned long Farrow_len; + //! Table of Farrow structure coefficients + /*! Number of vectors == Farrow_order. + * Each vector length == N_FSD. + * + * This is transposition of the constructor input table Farrow_coefs_in. + */ + std::vector<DSP::Float_vector> Farrow_coefs; + + //! variable storing currently evaluated output sample + DSP::Complex currentOutput; + //! current net delay value + DSP::Float epsilon; + + + //! Function calculates output sample and stores it in currentOutput + void CalculateOutputSample_real(void); + //! Function calculates output sample and stores it in currentOutput + void CalculateOutputSample_cplx(void); + + /*! false if Input Sample is expected in current clock cycle. + * Output sample generation must wait until input sample will be ready. + */ + bool InputSampleReady; + /*! false if Delay Sample is expected in current clock cycle. + * Output sample generation must wait until delay value will be ready. + */ + bool DelayReady; + + +// protected: +// void SetBlockInputClock(int InputNo, DSP::Clock_ptr InputClock); + + static void InputExecute_real(INPUT_EXECUTE_ARGS); + static void InputExecute_cplx(INPUT_EXECUTE_ARGS); + void Notify(DSP::Clock_ptr clock); //, bool State); + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + public: + + ////! InputClock == NULL <- auto detection at connection time + ///*! \param N_FSD_in - FSD filter length + // * \param order_in - Farrow structure order; + // * number of polynomial coefficients equals (order_in + 1) !!!. + // * \param Farrow_coefs_in - tablica wektor�w wsp�czynnik�w struktury Farrow'a. + // * N_FSD_in vectors of the length order_in with polynomial coefficients. + // * One polynomial for each FSD filter impulse response sample. /n + // * h[n] = p[n][0]*eps^order_in + p[n][1]*eps^(order_in-1) + ... +p[n][order_in] /n + // * n = 0, 1, ..., N_FSD-1 + // * + // * \param IsComplex true if complex input is used + // * \param InputClock clock for input signal + // * \param OutputClock clock for output signal + // */ + //DSP::u::Farrow(bool IsComplex, unsigned int N_FSD_in, unsigned int order_in, DSP::Float_ptr *Farrow_coefs_in, + // DSP::Clock_ptr InputClock, DSP::Clock_ptr OutputClock); + + //! InputClock == NULL <- auto detection at connection time + /*! \param Farrow_coefs_in - wektor wektor�w wsp�czynnik�w struktury Farrow'a. + * - liczba wektor�w wsp�czynnik�w (Farrow_coefs_in.size() == N_FSD) + * odpowiada d�ugo�ci odpowiedzi impulsowej filtru FD implementowanego przez struktur�, + * - d�ugo�� poszczeg�lnych wektor�w (Farrow_coefs_in[n].size() == p_Farrow+1) jest o jeden + * wi�ksza od rz�du wsp�czynnik�w wielomian�w aproksymuj�cych poszczeg�lne wsp�czynniki filtru FD + * + * One polynomial for each FSD filter impulse response sample. /n + * h[n] = p[n][0]*eps^order_in + p[n][1]*eps^(order_in-1) + ... +p[n][order_in] /n + * n = 0, 1, ..., N_FSD-1 + * + * \param IsComplex true if complex input is used + * \param InputClock clock for input signal + * \param OutputClock clock for output signal + */ + Farrow(const bool &IsComplex, const vector<DSP::Float_vector> &Farrow_coefs_in, + const DSP::Clock_ptr &InputClock, const DSP::Clock_ptr &OutputClock); + + ~Farrow(void); +}; +/**************************************************/ + +enum struct DSP::e::GardnerSamplingOptions : unsigned int { + //! all additional options off + none = 0, + //! block must activate output clock each time output sample is generated + activate_output_clock = 1, + //! block must output clock activation signal (signal working with input clock) + use_activation_signal = 2, + //! block must output input samples delay offsets (signal working with input clock) + use_delay_output = 4, + //! OQPSK signal mode: signal is sampled according to N_symb (which should be half of OQPSK symbol period) but error signal is calculated for 2*N_symb + OQPSK = 8, + }; +inline DSP::e::GardnerSamplingOptions DSP::e::operator|(DSP::e::GardnerSamplingOptions __a, + DSP::e::GardnerSamplingOptions __b) + { return DSP::e::GardnerSamplingOptions(static_cast<int>(__a) | static_cast<int>(__b)); } +inline DSP::e::GardnerSamplingOptions DSP::e::operator&(DSP::e::GardnerSamplingOptions __a, + DSP::e::GardnerSamplingOptions __b) + { return DSP::e::GardnerSamplingOptions(static_cast<int>(__a) & static_cast<int>(__b)); } + +/**************************************************/ +//! GardnerSampling - sample selection based on Gadner sampling time recovery algorithm +/*! + * + * Inputs and Outputs names: + * - Output: + * -# "out1", "out2", ... (complex valued) + * -# "out1.re", "out2.re", ... - real component\n + * "out1.im", "out2.im", ... - imag component + * -# "out" == "out1" (complex valued) + * -# "out.re" == "out1.re" - real component\n + * "out.im" == "out1.im" - imag component + * -# "act" - [OPTIONAL] clock activation signal (works with input clock if OutputClock == NULL) + * -# "offset" - [OPTIONAL] delay offset signal (works with input clock if OutputClock == NULL) + * - Input: + * -# "in1", "in2", ... (complex valued) + * -# "in1.re", "in2.re", ... - real component\n + * "in1.im", "in2.im", ... - imag component + * -# "in" == "in1" (complex valued) + * -# "in.re" == "in1.re" - real component\n + * "in.im" == "in1.im" - imag component + * + * + * \todo_later use DSP::Float_ptr y0, y1, y2 instead of DSP::Complex_ptr y0, y1, y2 + * to increase performance + * + * \todo_later output can be generated earlier when the interpolated values of y1 are available + * + * \todo <b>2006.08.03</b> + * -# separate processing function for single input signal + * . + */ +class DSP::u::GardnerSampling : public DSP::Block, public DSP::Source, public DSP::Clock_trigger +{ + private: + DSP::Float delay; + DSP::Float delay_1; //(all channels simultaneously) +// DSP::Float_ptr delay; + //! half of the sampling period + DSP::Float half_SamplingPeriod; + DSP::Float estimated_SamplingPeriod; + DSP::Float beta, korekta; //, tmp_korekta; + //! maximum allowed delay correction + DSP::Float max_korekta; + //! inner state (all channels simultaneously) + int state_1; +// int *state; //! inner state + + unsigned int NoOfChannels; + DSP::Complex_vector y0, y1, y2; + + //! construction options + DSP::e::GardnerSamplingOptions options; + //! true if in last execution of InputExecute output samples have been generated + bool output_generated; + //! true if block should work as source + bool use_OutputExecute; + + void Init( + DSP::Clock_ptr InputClock, + DSP::Clock_ptr OutputClock, + //! initial value of the sampling period + DSP::Float SamplingPeriod_in, + //! sampling period correction factor + DSP::Float beta_in, + //! maximum allowed delay correction + DSP::Float max_korekta_in, + //! number of simultaneously processed subchannels + unsigned int NoOfChannels_in, + DSP::e::GardnerSamplingOptions options_in); + + static void InputExecute_with_options(INPUT_EXECUTE_ARGS); + // static void InputExecute(DSP::Block *block, int InputNo, DSP::Float value, DSP::Component *Caller); + static void InputExecute_new(INPUT_EXECUTE_ARGS); + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + public: + DSP::Clock_trigger_ptr Convert2ClockTrigger(void) + { return GetPointer2ClockTrigger(); }; + + //! OBSOLETE constructor: backward compatibility. + /*! - ParentClock = NULL, + * - OutputClock = NULL + * - options = DSP_GS_none + */ + GardnerSampling(DSP::Float SamplingPeriod_in, //! initial value of the sampling period + DSP::Float beta_in, //! sampling period correction factor + DSP::Float max_korekta_in, //! maximum allowed delay correction + unsigned int NoOfChannels_in=1.0 //! number of simultaneously processed subchannels + ); + //! Gardner sampling block constructor + /*! Options (can be combination): + * - DSP::e::GardnerSamplingOptions::none - all additional options off + * - DSP::e::GardnerSamplingOptions::activate_output_clock - activates output clock each time output sample is generated + * - DSP::e::GardnerSamplingOptions::use_activation_signal - outputs clock activation signal for each cycle of the input clock if OutputClock == NULL otherwise output clock is used + * - DSP::e::GardnerSamplingOptions::use_delay_output - outputs input samples delay offsets for each cycle of the input clock if OutputClock == NULL otherwise output clock is used + * . + */ + GardnerSampling( + DSP::Clock_ptr InputClock, + DSP::Clock_ptr OutputClock, + //! initial value of the sampling period + DSP::Float SamplingPeriod_in, + //! sampling period correction factor + DSP::Float beta_in, + //! maximum allowed delay correction + DSP::Float max_korekta_in, + //! number of simultaneously processed subchannels + unsigned int NoOfChannels_in=1.0, + DSP::e::GardnerSamplingOptions options = DSP::e::GardnerSamplingOptions::none + ); + ~GardnerSampling(void); + + //! returns current estimated sampling period + DSP::Float GetSamplingPeriod(void); +}; + + + +//! PSK encoder - prepares symbols for PSK modulations +/*! + * \note Will become obsolete block, use DSP::u::SymbolMapper instead if possible. + * + * Supports DSP_PSK_type types: + * - BPSK, + * - DBPSK, + * - QPSK_A, <= QPSK symbols: { 1, -1, j, -j} + * - QPSK_B <= QPSK symbols: { 1+j, -1+j, 1-j, -1-j} + * . + * + * Inputs and Outputs names: + * - Output: + * -# "out" output symbol (complex valued) + * -# "out.re" - real part + * -# "out.im" - imag part + * - Input: + * -# "in" (complex (variants of QPSK) or real (variants of BPSK) valued) + * -# "in0" - first input bit + * -# "in1" - second input bit + */ +class DSP::u::PSKencoder : public DSP::Block +{ + private: + DSP::e::PSK_type Type; + int State_re, State_im; + int tmp_re, tmp_im; + //! used in InputExecute_XXXX for current symbol index evaluation + int symbol_index; + + static void InputExecute_BPSK(INPUT_EXECUTE_ARGS); + static void InputExecute_DBPSK(INPUT_EXECUTE_ARGS); + static void InputExecute_QPSK_A(INPUT_EXECUTE_ARGS); + static void InputExecute_QPSK_B(INPUT_EXECUTE_ARGS); + public: + PSKencoder(DSP::e::PSK_type type = DSP::e::PSK_type::BPSK); + ~PSKencoder(void); +}; + +//! Calculates constellations used in DSP::u::SymbolMapper and DSP::u::SymbolDemapper +/*! + * constellation_phase_offset - phase offset of constellation symbols [rad] (ignored in case of ASK) + */ +unsigned int getConstellation(DSP::Complex_vector &constellation, DSP::e::ModulationType type, const DSP::Float &constellation_phase_offset, const unsigned int &bits_per_symbol_in, bool &is_real); + +//! Serial to parallel converter +/*! Collects NoOfParallelOutputs samples from each input and outputs them in parallel (at the same clock cycle). + * + * Each input can be multivalued. For example for NoOfLinesPerInput == 1 the inputs are real valued while for NoOfLinesPerInput == 2 the inputs are complex valued. + * Output clock is NoOfParallelOutputs times slower than the input clock. + * + * Inputs and Outputs names: + * - Output: + * -# "out" parallel output all samples + * -# "out1", "out2", ... first,second, ... output sample (each with NoOfLinesPerInput lines) + * -# "out1.re", "out2.re", ... - real part (first line) of output samples + * -# "out1.im", "out2.im", ... - imag part (second line) of output samples (available only if NoOfLinesPerInput > 1) + * -# "out1[1]", "out1[2]", ... - first, second, ... line of output of first output sample ... + * - Input: + * -# "in" - input sample (all lines) + * -# "in.re" - real part of input sample + * -# "in.im" - imag part of input sample (available only if NoOfLinesPerInput > 1) + * -# "in1", "in2", ... first,second, ... input sample (for all NoOfLinesPerInput lines) + * + * \note Output clock cycle is equivalent to first input clock cycle. + * + * If NoOfParallelOutputs == 1 (input - output: one in one): + * - output can be generated in the same cycle as input comes, we just need to wait, + * - this case can be treated as improper input parameter + * . + * else: + * - at first output clock cycle not all inputs are ready, thus vector of zeros needs to be output, + * - at next clock cycles first input clock cycle starts and input values can be overwritten (a copy of previous state is needed) + */ +class DSP::u::Serial2Parallel : public DSP::Block, public DSP::Source +{ + private: + static void InputExecute(INPUT_EXECUTE_ARGS); + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + int no_of_parallel_outputs; //! number of inputs cycles before the output is generated + vector<DSP::Float> inputs; //! vector for input samples + vector<DSP::Float> outputs; //! vector for input samples + bool output_ready; //! set true when all inputs are collected in inputs vector + int current_cycle_no; // 0, 1, ..., no_of_inputs_per_output-1 + public: + + Serial2Parallel(const DSP::Clock_ptr &InputClock, + const unsigned int &NoOfParallelOutputs, + const unsigned int &NoOfLinesPerInput=1, + const vector<DSP::Float> &first_output_vector={}); + ~Serial2Parallel(void); +}; + +//! Parallel to serial converter +/*! Reads NoOfParallelInputs input samples in parallel and outputs them sample by sample in serial (for consecutive clock cycles). + * + * Each input can be multivalued. For example for NoOfLinesPerInput == 1 the inputs are real valued while for NoOfParallelInputs == 2 the inputs are complex valued. + * Output clock is NoOfParallelInputs times faster than the input clock. + * + * If reversed_order == true then last input is output first. + * + * Inputs and Outputs names: + * - Output: + * -# "out" - output sample (all lines) + * -# "out.re" - real part of output sample + * -# "out.im" - imag part of output sample (available only if NoOfLinesPerInput > 1) + * -# "out1", "oout2", ... first,second, ... input sample (for all NoOfLinesPerInput lines) + * - Input: + * -# "in" parallel input all samples + * -# "in1", "in2", ... first,second, ... input sample (each with NoOfLinesPerInput lines) + * -# "in1.re", "in2.re", ... - real part (first line) of input samples + * -# "in1.im", "in2.im", ... - imag part (second line) of input samples (available only if NoOfLinesPerInput > 1) + * -# "in1[1]", "in1[2]", ... - first, second, ... line of input of first input sample ... + * + * \note First output clock cycle is equivalent to input clock cycle. + */ +class DSP::u::Parallel2Serial : public DSP::Block, public DSP::Source +{ + private: + static void InputExecute(INPUT_EXECUTE_ARGS); + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + int no_of_parallel_inputs; //! number of output cycles per input cycle + vector<DSP::Float> inputs; //! vector for input samples for current clock cycle + bool ready; //! set true when all lines of the first input are collected in inputs vector and output can be generated for the first output clock cycle + unsigned int no_of_first_output_sample_lines_ready; // allows for detection when the first output sample can be generated + int current_out; //! index of currently generated output + public: + + Parallel2Serial(const DSP::Clock_ptr &InputClock, + const unsigned int &NoOfParallelInputs, + const unsigned int &NoOfLinesPerInput=1, + const bool &reversed_order = false); + ~Parallel2Serial(void); +}; + +//! DSP::u::SymbolMapper - prepares symbols for digital modulations based on binary input vector +/*! + * Supports DSP::e::ModulationType types: + * - DSP_MT_PSK, + * - DSP_MT_APSK, + * - \TODO DSP_MT_DPSK, + * - \TODO DSP_MT_QAM, + * - \TODO DSP_MT_FSK, + * - \TODO DSP_MT_OQPSK, + * . + * + * \TODO Implement differential encoding (DSP_MT_DPSK) & decoding + * \note First output symbol is the constellation symbol with index 0. + * \TODO Implement constellation phase offset (e.g. pi/4-QPSK) + * + * \note DSP_MT_PSK | DSP_MT_diff: y[0] = s[0]; y[n] = y[n-1] * s[n]; + * + * bits_per_symbol - number of bits per symbol. + * - bits_per_symbol = -1 (default) - default number of bits per symbol (based on modulation type type). + * constellation_phase_offset - phase rotation of constellation symbols [rad] + * - constellation_phase_offset = DSP::M_PIx1/4 for pi/4-QPSK + * + * Inputs and Outputs names: + * - Output: + * -# "out" output symbol (real or complex valued) + * -# "out.re" - real part + * -# "out.im" - imag part (only for complex valued modulations) + * - Input: + * -# "in" - vector of binary inputs: ("0" - in < 0.5, "1" - in >= 0.5) + * -# "in1","in2", ... - separate binary inputs; "in1" is the LSB of the symbol index in the constellation. + */ +class DSP::u::SymbolMapper : public DSP::Block +{ + private: + DSP::e::ModulationType Type; + + bool is_output_real; + unsigned int bits_per_symbol; + DSP::Complex_vector current_constellation; + + friend unsigned int getConstellation(DSP::Complex_vector &constellation, DSP::e::ModulationType type, const DSP::Float &constellation_phase_offset, const unsigned int &bits_per_symbol_in, bool &is_real); + vector <unsigned char> input_bits; + + static void InputExecute_bits(INPUT_EXECUTE_ARGS); + public: + + //! Returns true if block's output is real valued (single output line) + bool isOutputReal(void); + //! Returns number of input bits per output sample + unsigned int getBitsPerSymbol(void); + + //! Mapper selection based on modulation type and number of bits_per_symbol + SymbolMapper(DSP::e::ModulationType type = DSP::e::ModulationType::PSK, + const unsigned int &bits_per_symbol=-1, //! bits_per_symbol based on given constellation + const DSP::Float &constellation_phase_offset=0.0); + /*! Assuming + * bits_per_symbol = ceil(log2(constellation.size()); + * M = 2^bits_per_symbol; + * + * Each bits_per_symbol input bits (first as LSB) index symbol from constellation vector + * + * \TODO implement this variant + */ + SymbolMapper(const DSP::Complex_vector&constellation); + ~SymbolMapper(void); +}; + +//! DSP::u::SymbolDemapper - based on closest constellation point to current input symbol outputs corresponding bit stream +/*! \note This is counterpart of DSP::u::SymbolMapper. + * + * Supports DSP::e::ModulationType types: + * - PSK, + * - APSK, + * . + * + * \TODO Implement differential decoding + * + * bits_per_symbol - number of bits per symbol. + * - bits_per_symbol = -1 (default) - default number of bits per symbol (based on modulation type type). + * + * Inputs and Outputs names: + * - Output: + * -# "out" - all output bits + * -# "out1", "out2", ... - outputs for separate bits: "out1" is the LSB + * - Input: + * -# "in" - input symbols (real or complex valued (depending on modulation type) + * -# "in.re" - real part + * -# "in.im" - imag part (only for complex valued modulations) +*/ +class DSP::u::SymbolDemapper : public DSP::Block +{ + private: + DSP::e::ModulationType Type; + //! used for current symbol index evaluation + DSP::Complex input; // input sample + + bool is_input_real; + unsigned int bits_per_symbol; + DSP::Complex_vector current_constellation; + + friend unsigned int getConstellation(DSP::Complex_vector &constellation, DSP::e::ModulationType type, const DSP::Float &constellation_phase_offset, const unsigned int &bits_per_symbol_in, bool &is_real); + + static void InputExecute_constellation(INPUT_EXECUTE_ARGS); + + public: + //! Returns true if block expects input samples to be real valued (single input line) + bool isInputReal(void); + //! Returns number of input bits per output sample + unsigned int getBitsPerSymbol(void); + + //! Demapper selection based on modulation type and number of bits_per_symbol + SymbolDemapper(DSP::e::ModulationType type = DSP::e::ModulationType::PSK, + const unsigned int &bits_per_symbol=-1, //! bits_per_symbol based on given constellation + const DSP::Float &constellation_phase_offset=0.0); + + //! Demapper based on given constellation + /*! Assuming + * bits_per_symbol = ceil(log2(constellation.size()); + * M = 2^bits_per_symbol; + * + * Each bits_per_symbol input bits (first as LSB) index symbol from constellation vector + */ + SymbolDemapper(const DSP::Complex_vector &constellation); + ~SymbolDemapper(void); +}; + + + +//! PSK decoder - decodes PSK modulations symbols +/*! + * \note Will become obsolete block, use DSP::u::SymbolDemapper instead if possible. + * + * Supports DSP_PSK_type types: + * - BPSK, + * - DBPSK, + * - QPSK_A, <= QPSK symbols: { 1, -1, j, -j} + * - QPSK_B <= QPSK symbols: { 1+j, -1+j, 1-j, -1-j} + * . + * + * Inputs and Outputs names: + * - Output: + * -# "out" (complex (variants of QPSK) or real (variants of BPSK) valued) + * -# "out0" - first output bit + * -# "out1" - second output bit + * - Input: + * -# "in" output symbol (complex valued) + * -# "in.re" - real part + * -# "in.im" - imag part + */ +class DSP::u::PSKdecoder : public DSP::Block +{ + private: + DSP::e::PSK_type Type; + int State_re, State_im; + DSP::Float f_State_re, f_State_im; + + DSP::Float f_tmp_re, f_tmp_im; + int i_tmp_re, i_tmp_im; + + static void InputExecute_BPSK(INPUT_EXECUTE_ARGS); + static void InputExecute_DEBPSK(INPUT_EXECUTE_ARGS); + static void InputExecute_DBPSK(INPUT_EXECUTE_ARGS); + static void InputExecute_QPSK_A(INPUT_EXECUTE_ARGS); + static void InputExecute_QPSK_B(INPUT_EXECUTE_ARGS); + public: + PSKdecoder(DSP::e::PSK_type type = DSP::e::PSK_type::BPSK); + ~PSKdecoder(void); +}; + + +/**************************************************/ +//! Computes FFT of sequence made form inputs for the current instant +/*! Inputs and Outputs names: + * - Output (real or complex): + * -# "out_all" - all output lines + * -# "out" - first output (real or complex) + * -# "out.re", /n + * "out.im" + * -# "out1", "out2", ... - consecutive outputs (real or complex) + * -# "out1.re", "out2.re", .../n + * "out1.im", "out2.im", ... + * - Input (always complex): + * -# "in_all" - all input lines + * -# "in" - first input (complex) + * -# "in.re", /n + * "in.im" + * -# "in1", "in2", ... - consecutive inputs (complex) + * -# "in1.re", "in2.re", .../n + * "in1.im", "in2.im", ... + */ +class DSP::u::FFT : public DSP::Block +{ + private: + unsigned int K; + DSP::Fourier dft; + //DSP::Complex *input_buffer, *output_buffer; + DSP::Complex_vector input_buffer, output_buffer; + + static void InputExecute_cplx(INPUT_EXECUTE_ARGS); + static void InputExecute_real(INPUT_EXECUTE_ARGS); + + void RecalculateInitials(void); + + public: + //! FFT block + /*! K - FFT length, + */ + FFT(unsigned int K_in, bool AreInputsComplex = true); + ~FFT(void); +}; + +/**************************************************/ +//! Timing Error Detector - symbol timing error detector +/*! e[n] = (y[n] - y[n-2])*conj(y[n-1]) + * + * Inputs and Outputs names: + * - Output: + * - Input: + * -# "in" real or complex valued + * -# "in.re" - real component\n + * "in.im" - imag component + * . + * . + */ +class DSP::u::TimingErrorDetector : public DSP::Block +{ + private: + // index to symbols: previous, current and between + int n0, n1; // n2; + //DSP::Float_ptr Real_Buffer; + DSP::Float_vector Real_Buffer; + //DSP::Complex_ptr Cplx_Buffer; + DSP::Complex_vector Cplx_Buffer; + int N_symb; + + DSP::Float output_real; + DSP::Float output_real_n1; + + DSP::Complex output_cplx; + DSP::Complex output_cplx_n1; + + static void InputExecute_real_even(INPUT_EXECUTE_ARGS); + static void InputExecute_cplx_even(INPUT_EXECUTE_ARGS); + static void InputExecute_real_odd(INPUT_EXECUTE_ARGS); + static void InputExecute_cplx_odd(INPUT_EXECUTE_ARGS); + + public: + //! Timing Error Detector contructor. + /*! \param N - symbol length in [Sa], + * \param InputIsComplex - true if input signal is complex + */ + TimingErrorDetector(int N, bool InputIsComplex = false); + ~TimingErrorDetector(void); +}; + + +#endif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_modules_misc.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_modules_misc.h new file mode 100644 index 0000000000000000000000000000000000000000..2d084ca8711c540084579db8b96ff20a56d0f400 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_modules_misc.h @@ -0,0 +1,173 @@ +/*! \file DSPmodules_misc.h + * This is DSP engine miscellaneous components and sources + * definition module header file. + * + * \author Marek Blok + */ +#ifndef DSPmodules_miscH +#define DSPmodules_miscH + +//--------------------------------------------------------------------------- +#include <DSP_setup.h> +//--------------------------------------------------------------------------- +#include <DSP_modules.h> +#include <DSP_types.h> + +namespace DSP { + //Version of the morse code table file (*.mct) + const unsigned long Morse_Table_VER = 1; + + const unsigned long FontsEditEntriesNo = 1; + const unsigned long MorseCodeEditEntriesNo = 12; + const unsigned long MaxMorseCodeEntriesNumber = 1024; + + class TMorseTable; + namespace u { + class MORSEkey; + } +} + + +class DSP::TMorseTable +{ + private: + static int TablesNo; + static TMorseTable *FirstTable; + static const string &BaseDirectory; + + TMorseTable *NextTable; + + string FileName; + string TableDescription; + + void Save2File(const string &Name); + + static TMorseTable *Current; + + public: + bool LoadFromFile(const string &Name); + + string FontName[FontsEditEntriesNo]; + uint16_t FontCharset[FontsEditEntriesNo]; + string TestText[FontsEditEntriesNo]; + + uint16_t MorseCodeEntriesNo; + uint32_t MorseCode[MaxMorseCodeEntriesNumber]; //Converter to number +// char CharCode[MaxMorseCodeEntriesNumber]; + char CharCode[MaxMorseCodeEntriesNumber]; + char CharBCode[MaxMorseCodeEntriesNumber]; + unsigned char FontNo[MaxMorseCodeEntriesNumber]; + + static int FontCharset2Ind(uint32_t charset); + static uint32_t Ind2FontCharset(int ind); + static const string Ind2AnsiString(int ind); + + static uint32_t MorseCodeText2Number(const string &dot_dash_text); + /*! + * @param Number - numerical representation of MORSE code + * @return output text + */ + static string Number2MorseCodeText(uint32_t Number); + //! Converts character into Morse code number + /*! \warning works only for single character codes + */ + uint32_t Char2Number(char znak); + + int MorseCodeText2LetterInd(const string &dot_dash_text); + + TMorseTable(void); + ~TMorseTable(void); + + static int Count(void); //number of tables + const string Description(void); + static void SelectCurrent(int ind); + static TMorseTable *GetTable(int ind); + static int GetTableNo(TMorseTable *Table); + static void LoadTables(const string &BaseDir); + static void ReloadCurrentTable(void); + static bool DeleteCurrentTable(void); + static bool RenameCurrentTable(const string &NewName); + static void NewTable(void); + static void FreeTables(void); + static void SaveCurrent(void); + static TMorseTable *GetCurrent(void); +}; + + +/**************************************************/ +//! ON/OFF Morse code modulation key generator +/*! Inputs and Outputs names: + * - Output: + * -# "out", "out.re" - real valued keying signal + * - Input: none + * + * \todo include DSP::Randomization class if random dot/dash length will be used + */ +class DSP::u::MORSEkey : public DSP::Source // , public DSP::Randomization +{ + private: + void Init(DSP::Clock_ptr ParentClock); + TMorseTable MorseTable; + + string AsciiText; + //int current_char; // always first char is the current char + + //! current key state (1.0/0.0 == ON/OFF) + DSP::Float value; + int state, morse_state; + + string morse_text; + int current_morse_segment; + + float WPM; + long sampling_rate; + float dash2dot_ratio, space2dot_ratio; + int dot_len, dash_len, space_len; + + int ON_counter, OFF_counter; + + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + public: + //! set Keying speed in words per minute + /*! \todo user defined dash/dot ratio and space/dot ratio + * + * Speed is set based on the word PARIS + * P = di da da di = 2 dots, 2 dashes, 3 in-character spaces, 1 intercharacter space + * A = di da = 1 dot, 1 dash, 1 in-character space, 1 intercharacter space + * R = di da di = 2 dots, 1 dash, 2 in-character spaces, 1 intercharacter space + * I = di di = 2 dots, 0 dashes, 1 in-character space, 1 intercharacter space + * S = di di di = 3 dots, 0 dashes, 2 in-character spaces, 1 interword space + * + * Total: + * dots: 10 (x1 = 10) // dot_len + * dashes: 4 (x3 = 12) // dash_len = dash2dot_ratio * dot_len + * in-char spaces: 9 (x1 = 9) // dot_len + * interchar spaces: 4 (x3 = 12) // dash_len = dash2dot_ratio * dot_len + * interword spaces: 1 (x7 = 7) // space_len = space2dot_ratio * dot_len + * ------------------------------- + * = 50 + */ + void SetKeyingSpeed(float WPM_in, long sampling_rate_in, + float dash2dot_ratio_in = 3.0, float space2dot_ratio_in = 7.0); + static float GetDotLength(float WPM_in, long sampling_rate_in, + float dash2dot_ratio = 3.0, float space2dot_ratio = 7.0); + + bool LoadCodeTable(const string &filename); + + //! Changes manually current key state + /*! + * @param set_to_ON - true (key ON), false (key OFF) + */ + void SetKeyState(bool set_to_ON); + + //! Append string to the characters to transmit + void AddString(string AsciiText_in); + //! Append char to the characters to transmit + void AddChar(char znak); + + MORSEkey(DSP::Clock_ptr ParentClock, float WPM_in = 20.0, long sampling_rate_in = 8000); + ~MORSEkey(void); +}; + +#endif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_sockets.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_sockets.h new file mode 100644 index 0000000000000000000000000000000000000000..c97fd9aeff5c2b9dc8d4128c3a8a31c746c54b63 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_sockets.h @@ -0,0 +1,408 @@ +//--------------------------------------------------------------------------- +/*! \file DSP::Clock_ptr.h + * This is Socket Input/Output DSP module header file. + * + * Module blocks providing input from + * and output to sockets through winsock2. + * + * \author Marek Blok + */ +#ifndef DSP_SOCKET_H +#define DSP_SOCKET_H + +//#ifdef WIN32 +#if defined(WIN32) || defined(WIN64) + //! \warning required before #include <windows.h> for winsock2 support + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + + //#include <windows.h> + #if (_WIN32_WINNT < 0x0501) + // see http://msdn.microsoft.com/en-us/library/aa383745(VS.85).aspx + //#error wrong _WIN32_WINNT or WINVER + #define WINVER 0x501 + #define _WIN32_WINNT 0x501 + #endif + + #include <winsock2.h> + #include <ws2tcpip.h> + //#include "wspiapi_x.h" // support for freeaddrinfo on Win2000 + //#include <iphlpapi.h> + + + +// #include <windef.h> +#else + //#warning DSP_socket.cpp has been designed to be used with WIN32 + // https://www.techpowerup.com/forums/threads/c-c-sockets-faq-and-how-to-win-linux.56901/ + #define __NO_WINSOCK__ + + //#include <sys/types.h> + #include <sys/socket.h> + #include <arpa/inet.h> + #include <netdb.h> /* Needed for getaddrinfo() and freeaddrinfo() */ + #include <unistd.h> /* Needed for close() */ + #include <sys/ioctl.h> + #include <cerrno> + + typedef int SOCKET; + //const int INVALID_SOCKET = -1; + + const int WSAEWOULDBLOCK = EINPROGRESS; + const int WSAEALREADY = EALREADY; + const int WSAEINVAL = EINVAL; + const int WSAEISCONN = EISCONN; + //const int SOCKET_ERROR = -1; +#endif + +#include <DSP_IO.h> + + +//--------------------------------------------------------------------------- +#include <DSP_setup.h> +//--------------------------------------------------------------------------- +#include <DSP_modules.h> +#include <DSP_types.h> +//--------------------------------------------------------------------------- +//! \todo detect maximum allowed socket buffer size +namespace DSP { + const unsigned long Socket_buffer_size = 1024; + + class Socket; + namespace u { + class SocketInput; + class SocketOutput; + } + + namespace e { + enum struct SocketInfoDataType : unsigned int; + inline unsigned int get_value(const DSP::e::SocketInfoDataType& option); + + enum struct SocketStatus : unsigned int; + DSP::e::SocketStatus& operator|= (DSP::e::SocketStatus& left, + const DSP::e::SocketStatus& right); + DSP::e::SocketStatus& operator&= (DSP::e::SocketStatus& left, + const DSP::e::SocketStatus& right); + inline unsigned int get_value(const DSP::e::SocketStatus& option); + } +} + +enum struct DSP::e::SocketInfoDataType : unsigned int { + none = 0x0000, + Fp = 0x0001, + Offset = 0x0002, + UserData = 0x0003, + end = 0xffff // no more info data will be send +}; +inline unsigned int DSP::e::get_value(const DSP::e::SocketInfoDataType& option) { + return static_cast<std::underlying_type<DSP::e::SocketInfoDataType>::type>(option); +} + +enum struct DSP::e::SocketStatus : unsigned int { + none = 0, + connected = 1, + unconnected_mask = (0xffffff ^ connected), //xor + timeout = 2, + timeout_mask = (0xffffff ^ timeout), //xor + server = 4, + client_mask = (0xffffff ^ server), //xor + listen_active = 8, // listen socket active + listen_active_mask = (0xffffff ^ listen_active), //xor + error = 16, + closed = 32 +}; +DSP::e::SocketStatus& DSP::e::operator|= (DSP::e::SocketStatus& left, + const DSP::e::SocketStatus& right); +DSP::e::SocketStatus& DSP::e::operator&= (DSP::e::SocketStatus& left, + const DSP::e::SocketStatus& right); +inline unsigned int DSP::e::get_value(const DSP::e::SocketStatus& option) { + return static_cast<std::underlying_type<DSP::e::SocketStatus>::type>(option); +} + +// ***************************************************** // +// ***************************************************** // +//! Basic sockets support +/*! + * \todo implement non-blocking mechanisms with WSAAsyncSelect or WSAEventSelect functions. + * \todo implement server port selection algorithm + * \todo_later implement use of several server instances + * + * \warning supports only WINVER >= 501 + */ +class DSP::Socket +{ + private: + static bool winsock_initialized; + static int NoOfSocketObjects; + static const string DEFAULT_PORT; + #ifndef __NO_WINSOCK__ + static WSADATA wsaData; + #endif + + int iResult; + struct addrinfo *result; + struct addrinfo *ptr; + struct addrinfo hints; + + //! true is listening socket is ready + static bool listen_ready; + static SOCKET ListenSocket; + //! length of the server_objects_list + static int no_of_server_objects; + //! table of DSP::Socket created in server mode + static std::vector<DSP::Socket *> server_objects_list; + + string extract_hostname(const string& address_with_port); + string extract_port(const string& address_with_port, const string& default_port); + + static void close_socket(); + public: + static void close_socket(SOCKET &socket_to_close); + + protected: + //! ID number for the current server object + /*! This number is used to identify DSP::Socket + * object to which the given incoming connection + * is addressed. + */ + uint32_t ServerObjectID; + //! true if server or client socket is ready + + bool works_as_server; + bool socket_ready; + //! used for server or client connections + SOCKET ConnectSocket; + //! used for client connections + //SOCKET ClientSocket; + + //! stores current socket state + /*! \note derived class should update this state variable + */ + DSP::e::SocketStatus current_socket_state; + + bool Init_socket(void); + + bool InitClient(const string &address_with_port); + bool InitServer_ListenSocket(const string &address_with_port); + bool InitServer(void); //uint32_t ServerObjectID_in); + + //! Attempts to accepts single connections if there is any in the listen queue + /*! Returns true on success. + * \todo (note) The DSP::Socket object which will benefit (get connected) + * depends on connection ID send through accepted connection. + * \warning works only for server objects + */ + static bool TryAcceptConnection(void); + //! Attempts to establish connection with the server for the current DSP::Socket object + /*! Returns true on success. + * - ServerObjectID == 0x00000000 - connect with any server object + * - ServerObjectID != 0x00000000 - connect only with server object which has given ID + * . + * \warning works only for client objects + */ + bool TryConnect(uint32_t ServerObjectID); + public: + //! \note port should be includes in address + /*! + * @param address with optional port number after colon + * @param run_as_client + * @param ServerObjectID_in - if run_as_client == false it is current object ID else it is peer object ID + * + * \note ServerObjectID_in == 0x00000000 means : accept all IDs + */ + Socket(const string &address_with_port, bool run_as_client, uint32_t ServerObjectID_in); + ~Socket(void); + + //! Waits until connection with current object is made + bool WaitForConnection(bool stop_on_fail = false); + + bool is_socket_valid(); + static bool is_socket_valid(const SOCKET &socket_to_check); + static bool is_socket_error(const int &iResult); + int GetLastError(); + + DSP::e::SocketStatus GetSocketStatus(void); +}; + +//! Socket multichannel data input block +/*! Inputs and Outputs names: + * - Output: + * -# "out" - real, complex or multiple-components + * -# "out.re" - first channel (real component)\n + * "out.im" - second channel (imag component) + * -# "out1", "out2", ... - i-th channel input + * - Input: none + */ +class DSP::u::SocketInput : public DSP::File, public DSP::Socket, public DSP::Source +{ + private: + DSP::e::SampleType SampleType; + + //! size of the output buffer in DSP::Float * NoOfOutputs + unsigned long BufferSize; + DSP::Float_vector Buffer; + unsigned long BufferIndex; + + unsigned long BytesRead; + unsigned long SamplingRate; + + //! in bits (all channels together) + unsigned int InputSampleSize; + //! in bytes size of the buffer (RawBuffer) used in socket access + unsigned long inbuffer_size; + std::vector<uint8_t> RawBuffer; + + //! number of bytes read in previous socket access + /*! \warning is initialized with DSP_FILE_READING_NOT_STARTED + */ + unsigned long LastBytesRead_counter; + + //! stores parent clock in case we must stall it for some time + DSP::Clock *my_clock; + + void Init(DSP::Clock_ptr ParentClock, + unsigned int OutputsNo = 1, //just one channel + DSP::e::SampleType sample_type = DSP::e::SampleType::ST_float); + + static bool OutputExecute(OUTPUT_EXECUTE_ARGS); + + //! true if socket info data has been read + bool SocketInfoData_received; + //! sampling rate - received from peer + long Fp; + //! number of cycles to skip before first data - received from peer + long Offset; + //! reads connection data sent from the DSP::u::SocketOutput + /*! \note this must be done right after the connection is established + * and before any data are received. + */ + bool ReadConnectionData(void); + + bool SetSkip(long long Offset_in); + + public: + //! \note address may include port number after colon + SocketInput(DSP::Clock_ptr ParentClock, + const string &address_with_port, bool run_as_client, + uint32_t ServerObjectID, + unsigned int NoOfChannels=1, + DSP::e::SampleType sample_type=DSP::e::SampleType::ST_float); + ~SocketInput(void); + + //! returns number of bytes read during last socket access + /*!\note return zero if connections has been closed + * \warning returns DSP_FILE_READING_NOT_STARTED if reading + * not started already + */ + unsigned long GetBytesRead(void); + //! returns sampling rate of audio sample + unsigned long GetSamplingRate(void); + + //! Returns raw sample size in bytes corresponding to given SampleType + /*! \note For SampleType = DSP::e::SampleType::ST_none returns internal raw sample size + * used in DSP::u::FileInput. + * + * \warning Sample size is given in bits and encloses all channels + */ + unsigned int GetSampleSize(DSP::e::SampleType SampleType = DSP::e::SampleType::ST_none); + + //! Returns raw buffer size in bytes needed for NoOfSamples samples. + /*! If NoOfSamples == 0 return allocated internal raw buffer size. + */ + unsigned long GetRawBufferSize(unsigned long NoOfSamples = 0); + //! Returns DSP::Float buffer size needed for SizeInSamples samples. + /*! If SizeInSamples == 0 return allocated internal DSP::Float buffer size. + * + * \note Returned value is NoOfSamples * NoOfChannels. + */ + unsigned int GetFltBufferSize(unsigned int NoOfSamples = 0); + + //! Reads segment for file and stores it in the buffer + /*! Returns number of read bytes. + */ + unsigned int ReadSegmentToBuffer( + // //! buffer size in samples + // unsigned int buffer_size, + // //! Raw buffer which will be used internally by the function + // /*! \note raw_buffer_size == buffer_size * sample_size / 8. + // * \note Raw sample size can be determined with + // * DSP::u::FileInput::GetSampleSize function + // * + // * \warning this buffer must be allocated and deleted by the user. + // */ + // char *raw_buffer, + //! Buffer where read data will be stored in DSP::Float format + /*! \note size == buffer_size * no_of_channels + * \warning this buffer must be allocated and deleted by the user. + */ + DSP::Float_vector &flt_buffer + ); +}; + +//! Creates object for sending signals through socket +/*! + * InputsNo - number of inputs (one channel per input) + * + * Inputs and Outputs names: + * - Output: none + * - Input: + * -# "in" - real or complex + * -# "in.re" - first channel (real component)\n + * "in.im" - second channel (imag component if exists) + * -# "in1", "in2" - i-th channel input + */ +class DSP::u::SocketOutput : public DSP::Socket, public DSP::Block +{ + private: + unsigned long BufferSize; + DSP::Float_vector Buffer; + unsigned long BufferIndex; + + //! Type of samples send into socket + DSP::e::SampleType SampleType; + //! output sample size in bits (all channels) + unsigned int OutputSampleSize; + //! size of the buffers used for socket + unsigned long outbuffer_size; + std::vector<uint8_t> RawBuffer; + + + //! To be used in constructor + bool Init(void); + //! Prepares buffers for playing and sends it to the audio device + /*! saturation logic should be implemented */ + void FlushBuffer(void); + + void Init(unsigned int InputsNo=1, //just one channel + DSP::e::SampleType sample_type=DSP::e::SampleType::ST_float); + + static void InputExecute(INPUT_EXECUTE_ARGS); + + //! true if socket info data has been sent + bool SocketInfoData_sent; + //! Sends connection data to the DSP::u::SocketInput + /*! \note this must be done right after the connection is established + * and before any data are sent. + */ + bool SendConnectionData(void); + + public: + //! \note address should maycontain port number after colon + /*! + * @param address_with_port + * @param run_as_client + * @param ServerObjectID - if run_as_client == false it is current object ID else it is peer object ID + * @param NoOfChannels + * @param sample_type + */ + SocketOutput( + const string & address_with_port, bool run_as_client, + uint32_t ServerObjectID, + unsigned int NoOfChannels=1, + DSP::e::SampleType sample_type=DSP::e::SampleType::ST_float); + ~SocketOutput(void); +}; + +#endif // DSP_SOCKET_H + diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_types.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_types.h new file mode 100644 index 0000000000000000000000000000000000000000..d9b0948f4c86b439f0e03501f1f5c8947f27e08f --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/DSP_types.h @@ -0,0 +1,650 @@ +/*! \file DSP_types.h + * This is DSP engine types definition header file. + * + * \author Marek Blok + */ +#ifndef DSP_types_H +#define DSP_types_H + +#ifndef _USE_MATH_DEFINES + #define _USE_MATH_DEFINES +#endif +#include <cmath> +#include <limits.h> +#include <vector> +#include <string> +#include <functional> + +using namespace std; +//--------------------------------------------------------------------------- +#include <DSP_setup.h> +//--------------------------------------------------------------------------- + +#define MAX_NO_OF_SIGNAL_ACTIVATED_CLOCKS 100 +//#define DSP_FILE_NAME_LEN 1024 +#define DSP_FILE_READING_NOT_STARTED UINT_MAX + +//--------------------------------------------------------------------------- +#define UNUSED_ARGUMENT(x) (void)x +#ifdef __DEBUG__ + #define UNUSED_DEBUG_ARGUMENT(x) (void)x + #define UNUSED_RELEASE_ARGUMENT(x) {} +#else + #define UNUSED_DEBUG_ARGUMENT(x) {} + #define UNUSED_RELEASE_ARGUMENT(x) (void)x +#endif + +//--------------------------------------------------------------------------- +//! main DSPE library namespace +namespace DSP { + class output; + //typedef DSP_output * DSP_output_ptr; + class input; + //typedef DSP_input * DSP_input_ptr; +} + +namespace DSP { + class File; + typedef File * File_ptr; + + class Clock_trigger; + typedef Clock_trigger * Clock_trigger_ptr; + + class Component; + typedef Component * Component_ptr; + + class Block; + typedef Block * Block_ptr; + class Source; + typedef Source * Source_ptr; + + class Macro; + typedef Macro * Macro_ptr; + + namespace u { + class Copy; + typedef Copy * Copy_ptr; + + class Switch; + typedef Switch * Switch_ptr; + } +} + +namespace DSP { + class Clock; + typedef Clock * Clock_ptr; +} + +namespace DSP { + namespace e { + enum struct ComponentType : unsigned int; + ComponentType operator|(ComponentType __a, ComponentType __b); + ComponentType operator&(ComponentType __a, ComponentType __b); + + enum struct SampleType; + enum struct FileType; + enum struct OffsetMode; + enum struct PSK_type; + enum struct ModulationType; + enum struct BufferType; + } + + class T_WAVEchunk; + typedef T_WAVEchunk * T_WAVEchunk_ptr; +} + +//! Definition of floating point type used in the DSP module +#define DSP_USE_float + +#ifdef DSP_USE_float +// typedef float DSP::Float; + namespace DSP { + typedef float Float; + } + + #define COS cosf + #define SIN sinf + #define EXP expf + #define FMOD fmodf + #define CEIL ceilf + #define FLOOR floorf + #define SQRT sqrtf + #define FABS fabsf + #define POW powf + #define ATAN2 atan2f + +#else + namespace DSP { + typedef double DSP::Float; + } + + #define COS cos + #define SIN sin + #define EXP exp + #define FMOD fmod + #define CEIL ceil + #define FLOOR floor + #define SQRT sqrt + #define FABS fabs + #define POW pow + #define ATAN2 atan2 +#endif + +namespace DSP { + const long double M_PIx1_prec = 3.14159265358979323846264338328; + const long double M_PIx2_prec = 6.28318530718058647692528676656; + + // and DSP::Float precision + const DSP::Float M_Ef = DSP::Float(M_E); + const DSP::Float M_LOG2Ef = DSP::Float(M_LOG2E); + const DSP::Float M_LOG10Ef = DSP::Float(M_LOG10E); + const DSP::Float M_LN2f = DSP::Float(M_LN2); + const DSP::Float M_LN10f = DSP::Float(M_LN10); + const DSP::Float M_PIf = DSP::Float(M_PI); + const DSP::Float M_PI_2f = DSP::Float(M_PI_2); + const DSP::Float M_PI_4f = DSP::Float(M_PI_4); + const DSP::Float M_1_PIf = DSP::Float(M_1_PI); + const DSP::Float M_2_PIf = DSP::Float(M_2_PI); + const DSP::Float M_2_SQRTPIf = DSP::Float(M_2_SQRTPI); + const DSP::Float M_SQRT2f = DSP::Float(M_SQRT2); + const DSP::Float M_SQRT1_2f = DSP::Float(M_SQRT1_2); + + const DSP::Float M_PIx2 = DSP::Float(M_PIx2_prec); + const DSP::Float M_PIx1 = DSP::Float(M_PIx1_prec); + + typedef DSP::Float * Float_ptr; + typedef long double Prec_Float; //high precition float type + class Complex; + + typedef DSP::Prec_Float * Prec_Float_ptr; + typedef DSP::Complex * Complex_ptr; + + typedef void * void_ptr; + + + typedef std::vector<DSP::Float > Float_vector; + typedef std::vector<DSP::Prec_Float > Prec_Float_vector; + typedef std::vector<DSP::Complex > Complex_vector; + + //! Pointer to the callback function + /*! void func(unsigned int NoOfInputs, DSP::Float_ptr InputSamples, + * unsigned int NoOfOutputs, DSP::Float_ptr OutputSamples, + * DSP::void_ptr *UserDataPtr, unsigned int UserDefinedIdentifier, + * DSP::Component_ptr Caller) + * + * UserDataPtr - default value is NULL, in this variable user can store + * the pointer to his own data structure + * + * This callback function apart from calls when input samples are + * to be processed is called two additional times: + * -# call from block constructor with NoOfInputs = DSP::Callback_Init; + * this is when the user can initiate UserData structure + * and set its pointer to UserDataPtr. + * -# call from block destructor with NoOfInputs = DSP::Callback_Delete; + * this is when the user can free UserData structure. + * + */ + typedef void (*Callback_ptr)(unsigned int, DSP::Float_ptr, + unsigned int, DSP::Float_ptr, + DSP::void_ptr *, unsigned int, + DSP::Component_ptr); + + //! Pointer to the buffer callback function + /*! void func(unsigned int NoOfInputs, + * unsigned int NoOfOutputs, DSP::Float_ptr OutputSamples, + * DSP::void_ptr *UserDataPtr, unsigned int UserDefinedIdentifier, + * DSP::Component_ptr Caller) + * + * UserDataPtr - default value is NULL, in this variable user can store + * the pointer to his own data structure + * + * This callback function apart from calls when input samples are + * to be processed is called two additional times: + * -# call from block constructor with NoOfInputs = DSP::Callback_Init; + * this is when the user can initiate UserData structure + * and set its pointer to UserDataPtr. + * -# call from block destructor with NoOfInputs = DSP::Callback_Delete; + * this is when the user can free UserData structure. + * + */ + typedef void (*Buffer_callback_ptr)(unsigned int, + unsigned int, DSP::Float_vector &, + DSP::void_ptr *, unsigned int, + DSP::Component_ptr); + + //! Pointer to the notification callback function + /*! void func(DSP::Component_ptr Caller, unsigned int UserDefinedIdentifier) + */ + typedef void (*Notify_callback_ptr)(DSP::Component_ptr, unsigned int); + + //! Pointer to the external sleep function implementation + /*! void func(uint32_t time) + */ + typedef void (*ExternalSleep_ptr)(uint32_t); +} + +class DSP::Complex +{ + public: + DSP::Float re; + DSP::Float im; + + Complex(void) + { + re=0.0; im=0.0; + } + Complex(const DSP::Float& re_in) + { + re=re_in; im=0.0; + } + template <typename T> + Complex(const T& re_in, const T& im_in) + { + re=(DSP::Float)re_in; im=(DSP::Float)im_in; + } + + void set(DSP::Float re_in) + { re=re_in; im=0.0; }; + void set(DSP::Float re_in, DSP::Float im_in) + { re=re_in; im=im_in; }; + void set(double re_in, double im_in) + { re=(DSP::Float)re_in; im=(DSP::Float)im_in; }; + void set(DSP::Complex number) + { re=number.re; im=number.im; }; + + friend const DSP::Complex operator* (const DSP::Complex& left, + const DSP::Complex& right) + { +// (a.re+j*a.im)*(b.re+j*b.im) +// a.re*b.re-a.im*b.im+j*(a.re*b.im+a.im*b.re) + return DSP::Complex(left.re*right.re-left.im*right.im, + left.re*right.im+left.im*right.re); + } + + friend const DSP::Complex operator+ (const DSP::Complex& left, + const DSP::Complex& right) + { + return DSP::Complex(left.re+right.re, left.im+right.im); + } + + friend const DSP::Complex operator- (const DSP::Complex& left, + const DSP::Complex& right) + { + return DSP::Complex(left.re-right.re, left.im-right.im); + } + + friend DSP::Complex& operator+= (DSP::Complex& left, + const DSP::Complex& right) + { + left.re+=right.re; + left.im+=right.im; + return left; + } + + void add(DSP::Complex number) + { + re+=number.re; + im+=number.im; + } + + void sub(DSP::Complex number) + { + re-=number.re; + im-=number.im; + } + + void divide_by(DSP::Complex factor) + { + DSP::Float mod; + + mod=factor.re*factor.re+factor.im*factor.im; + mod=SQRT(mod); + factor.re/=mod; factor.im/=(-mod); + re/=mod; im/=mod; + + multiply_by(factor); + } + + void multiply_by(DSP::Complex factor) + { + DSP::Float temp; + + temp=re; + re=temp*factor.re-im*factor.im; + im=temp*factor.im+im*factor.re; + + /* _bug this is temporary solution but problem probably lays + * somewhere else + #ifdef DSP_USE_float + unsigned char *s; + + s=(unsigned char *)(&re)+3; + if (((*s)<<1)==0) + re=0.0; + s=(unsigned char *)(&im)+3; + if (((*s)<<1)==0) + im=0.0; +// #error Float problem + #endif + */ + } + + void multiply_by_conj(DSP::Complex factor) + { + DSP::Float temp; + + temp=re; + re= temp*factor.re+im*factor.im; + im=-temp*factor.im+im*factor.re; + } + + void multiply_by(DSP::Float factor) + { + re*=factor; + im*=factor; + } + + DSP::Float abs(void) + { + return SQRT(re*re+im*im); + } + + friend DSP::Float abs(const DSP::Complex& val) + { + return SQRT(val.re*val.re+val.im*val.im); + } + + // square of absolute value of complex number + friend DSP::Float abs2(const DSP::Complex& val) + { + return val.re*val.re+val.im*val.im; + } + + //! result for -1+j0 should rather be -PI but is +PI + /*! However the atan2 function is extremely sensitive to + * quantization noise of the imaginary part of the sample. + */ + DSP::Float angle(void) + { +// return -atan2(-im, re); + return ATAN2(im, re); + } +}; + +//! component type +enum struct DSP::e::ComponentType : unsigned int { + none=0, + block=1, + source=2, + mixed=3, + copy=4 +}; +inline DSP::e::ComponentType DSP::e::operator|(DSP::e::ComponentType __a, DSP::e::ComponentType __b) +{ + return static_cast<DSP::e::ComponentType>(static_cast<std::underlying_type<DSP::e::ComponentType>::type>(__a) + | static_cast<std::underlying_type<DSP::e::ComponentType>::type>(__b)); +} +inline DSP::e::ComponentType DSP::e::operator&(DSP::e::ComponentType __a, DSP::e::ComponentType __b) +{ + return static_cast<DSP::e::ComponentType>(static_cast<std::underlying_type<DSP::e::ComponentType>::type>(__a) + & static_cast<std::underlying_type<DSP::e::ComponentType>::type>(__b)); +} + +//! Enums for different Sample Types for file IO operations +/*! - DSP::e::SampleType::ST_float : C++ float (32bit floating point) + * - DSP::e::SampleType::ST_scaled_float : C++ float * 0x8000 (32bit floating point scalled by 0x8000 for 32bit PCM wav file) + * - DSP::e::SampleType::ST_double : C++ double (64bit floating point) + * - DSP::e::SampleType::ST_long_double : C++ long double (80bit floating point) + * - DSP::e::SampleType::ST_short : C++ short (16bit signed integer) + * - DSP::e::SampleType::ST_uchar : C++ unsigned char (8bit unsigned integer with bias (0x80)) + * - DSP::e::SampleType::ST_bit : 1 bit stream (MSB first) + * - DSP::e::SampleType::ST_bit_reversed : reversed 1 bit stream (LSB first) + * - DSP::e::SampleType::ST_bit_text : 1 bit stream writen as a text (0 & 1 characters) + * - DSP::e::SampleType::ST_tchar : 8-bit char (text) - no scalling of input data (only DSP::u::FileOutput with DSP::e::FileType::FT_raw) + * . + * + * Fixed <b>2006.06.30</b> Changed name from DSP_FileType to DSP_SampleType + * and prefix from DSP::e::FileType::FT_ to DSP_ST_: + */ +enum struct DSP::e::SampleType { + ST_none = 0, ST_float = 1, ST_scaled_float = 2, + ST_uchar = 3, ST_short = 4, ST_int = 5, + ST_bit = 6, ST_bit_reversed = 7, ST_bit_text = 8, + ST_double = 9, ST_long_double = 10, + ST_tchar = 11}; + +//! Enums for different File Types == file header type for file IO operations +/*! -# DSP::e::FileType::FT_raw : no header just raw data + * -# DSP::e::FileType::FT_flt : floating point content file with additional info + * - See ::T_FLT_header + * . + * -# DSP::e::FileType::FT_wav : Windows WAV file (uncompressed/PCM) + * -# DSP::e::FileType::FT_tape : *.tape file + * - See ::T_TAPE_header + * . + * . + */ +enum struct DSP::e::FileType { + FT_raw = 0, + FT_flt = 1, + // FT_no_scaling = 2, + FT_flt_no_scaling = 3, // (FT_flt | FT_no_scaling) + FT_wav = 4, + FT_tape = 5}; + +//! Enums for DSP::u::FileOutput +enum struct DSP::e::OffsetMode { + //! from beginning (after header) + standard = 0, + //! from current position + skip = 1}; + +//! Enums for PSK type +enum struct DSP::e::PSK_type { + BPSK=0, + DEBPSK=1, + DBPSK=2, + QPSK_A=3, + QPSK_B=4, + DQPSK=5, + pi4_QPSK=6 + }; + +//! Enums for Modulation types +enum struct DSP::e::ModulationType { + PSK=0, + ASK=1, + DPSK=2, // differential variant of the PSKodulation + QAM=3 + }; + +//! Enums for DSP::u::OutputBuffer +enum struct DSP::e::BufferType { + standard = 0, + cyclic = 1, + stop_when_full = 2 + }; + +namespace DSP { + const uint32_t CallbackID_mask = 0x00ffffff; + const uint32_t CallbackID_signal_mask = 0xff000000; + const uint32_t CallbackID_signal_start = 0x01ffffff; + const uint32_t CallbackID_signal_stop = 0x02ffffff; + +//#define UINT_MAX 0xffffffff + const uint32_t MaxOutputIndex = (UINT_MAX-2); + const uint32_t MaxInputIndex = (UINT_MAX-2); +//! DSP::Block::FindOutputIndex_by_InputIndex constants + const uint32_t Callback_Init = (UINT_MAX); + const uint32_t Callback_Delete = (UINT_MAX-1); + const uint32_t FO_TheOnlyOutput = (UINT_MAX-1); + const uint32_t FO_NoOutput = (UINT_MAX); + const uint32_t FO_NoInput = (UINT_MAX); +} + +namespace DSP { +//! Pointer to the DSP::Block input callback function +/*! void func(DSP::Block_ptr block, unsigned int InputNo, DSP::Float value, DSP::Component *Caller) + * + * \note In release mode last parameter (DSP::Component *) is skipped + */ +#ifdef __DEBUG__ + typedef void (*Block_Execute_ptr)(const DSP::Block_ptr, unsigned int, DSP::Float, const DSP::Component_ptr); +#else + typedef void (*Block_Execute_ptr)(const DSP::Block_ptr, unsigned int, DSP::Float); +#endif +} + +//! Pointer to the DSP::Source output callback function +/*! bool func(DSP::Source_ptr source, DSP::Clock_ptr clock) + * + * This function should return false when source is not ready yet + * (in such case this function will be called again later still for the same clock cycle), + * and true when source was ready and have already sent the output value(s). + * + * \note In release mode last parameter (DSP::Clock_ptr) is skipped + */ +namespace DSP { + #ifdef __DEBUG__ + typedef bool (*Source_Execute_ptr)(const DSP::Source_ptr, const DSP::Clock_ptr); + #else + typedef bool (*Source_Execute_ptr)(const DSP::Source_ptr); + #endif +} + +#ifdef __DEBUG__ + #define INPUT_EXECUTE_ARGS DSP::Block_ptr block, unsigned int InputNo, DSP::Float value, DSP::Component_ptr Caller + #define EXECUTE_PTR(block, InputNo, value, Caller) Execute_ptr((DSP::Block_ptr)block, InputNo, value, (DSP::Component_ptr)Caller) + #define EXECUTE_INPUT_CALLBACK(InputExecute, block, InputNo, value, Caller) InputExecute(block, InputNo, value, Caller) + + #define OUTPUT_EXECUTE_ARGS DSP::Source_ptr source, DSP::Clock_ptr clock + #define OUTPUT_EXECUTE_PTR(source, clock) OutputExecute_ptr((DSP::Source_ptr)source, (DSP::Clock_ptr)clock) +#else + #define INPUT_EXECUTE_ARGS DSP::Block_ptr block, unsigned int InputNo, DSP::Float value + #define EXECUTE_PTR(block, InputNo, value, Caller) Execute_ptr((DSP::Block_ptr)block, InputNo, value) + #define EXECUTE_INPUT_CALLBACK(InputExecute, block, InputNo, value, Caller) InputExecute(block, InputNo, value) + + #define OUTPUT_EXECUTE_ARGS const DSP::Source_ptr source + #define OUTPUT_EXECUTE_PTR(source, clock) OutputExecute_ptr((DSP::Source_ptr)source) +#endif + + +namespace DSP { + namespace u { + class AudioInput; + class AudioOutput; + } + +// typedef std::function<bool(const DSP::e::SampleType &, const std::vector<char> &)> input_callback_function; + // https://isocpp.org/wiki/faq/pointers-to-members#typedef-for-ptr-to-memfn + //! defining a type for pointer to member funtion of DSP::u::AudioInput + typedef bool(DSP::u::AudioInput::*input_callback_function)(const DSP::e::SampleType &, const std::vector<char> &); + //! defining a type for pointer to member funtion of DSP::u::AudioOutput + typedef bool(DSP::u::AudioOutput::*output_callback_function)(const DSP::e::SampleType &, const std::vector<char> &); + + //! Base class for classes implementing sound card support for DSP::u::AudioInput and DSP::u::AudioOutput + /*! \TODO convert WMM support in DSP::u::AudioInput and DSP::u::AudioOutput into support through WMM_object_t + */ + class SOUND_object_t { + private: + DSP::u::AudioInput * AudioInput_object; + //bool (DSP::u::AudioInput::*AudioInput_callback)(const DSP::e::SampleType &InSampleType, const std::vector<char> &wave_in_raw_buffer); + input_callback_function AudioInput_callback; + DSP::u::AudioOutput * AudioOutput_object; + output_callback_function AudioOutput_callback; + + //static unsigned long Next_CallbackInstance; + unsigned long Current_CallbackInstance; + static std::vector<DSP::SOUND_object_t *> CallbackSoundObjects; + static unsigned long get_free_CallbackInstance(void); + + protected: + long int get_current_CallbackInstance(); + static const DSP::SOUND_object_t * get_CallbackSoundObject(const long int &instance_number); + + public: + virtual void log_driver_data() = 0; + + virtual unsigned int select_input_device_by_number(const unsigned int &device_number=UINT_MAX) = 0; + virtual unsigned int select_output_device_by_number(const unsigned int &device_number=UINT_MAX) = 0; + + virtual long open_PCM_device_4_output(const int &no_of_channels, int no_of_bits, const long &sampling_rate, const long &audio_outbuffer_size = -1) = 0; + virtual long open_PCM_device_4_input(const int &no_of_channels, int no_of_bits, const long &sampling_rate, const long &audio_outbuffer_size = -1) = 0; + virtual bool close_PCM_device_input(void) = 0; + virtual bool close_PCM_device_output(void) = 0; + + //! returns true is the playback is on + virtual bool is_device_playing(void) = 0; + //! initializes playback stopping + virtual bool stop_playback(void) = 0; + //! returns true is the sound capture is on + virtual bool is_device_recording(void) = 0; + //! returns true is the sound capture is on + virtual bool stop_recording(void) = 0; + + //! \note values stored in float_buffer might be altered + virtual long append_playback_buffer(DSP::Float_vector &float_buffer)=0; + //! Starts sound capture + virtual bool start_recording(void) = 0; + + + // https://stackoverflow.com/questions/8865766/get-a-pointer-to-objects-member-function + /*! Returns false if callbacks are not supported for recording + */ + virtual bool is_input_callback_supported(void) = 0; + /*! Registers callback for input buffer data ready. Returns false if callbacks are not supported + * If this method fails or is not used the SOUND_ocject falls back into non-callback mode. + * + * Registers as a callback function that is a member function of the AudioInput class along with the object of the AudioInput class for which it should be called. + * - bool input_callback_function(const DSP::e::SampleType &InSampleType, const std::vector<char> &wave_in_raw_buffer); + * + * The callback function will be called by the SOUND_object when sound card's input buffer is ready. + * The callback function has to return true when it processed the input buffer or false when it cannot to process it. + * On false the SOUND_object most probably will discard the buffer. Nevertheless it can try to call the callback again for the same data. + */ + bool register_input_callback_object(DSP::u::AudioInput *callback_object, input_callback_function &cp); + //! Returns pointer to DSP::u::AudioInput for which callback is registered. + /*! \note If this function returns NULL, callbacks are not used even if they are supported. + */ + DSP::u::AudioInput *get_input_callback_object(); + protected: + //! \note this method should be used only by descending classes + bool input_callback_call(const DSP::e::SampleType &InSampleType, const std::vector<char> &wave_in_raw_buffer); + public: + //! If enough audio data are already available then fills InSampleType and wave_in_raw_buffer + /*! return true on success or false if the data are not available + * \note this method should be used only if callbacks are not active + */ + virtual bool get_wave_in_raw_buffer(DSP::e::SampleType &InSampleType, std::vector<char> &wave_in_raw_buffer) = 0; + + /*! Returns false if callbacks are not supported for playback + */ + virtual bool is_output_callback_supported(void) = 0; + /*! Returns false if callbacks are not supported + * + * Registers as a callback function that is a member function of the AudioOutput class along with the object of the AudioOutput class for which it should be called. + * - bool output_callback_function(const DSP::e::SampleType &OutSampleType, const std::vector<char> &wave_out_raw_buffer); + * + * The callback function will be called by the SOUND_object when new sound card's output buffer can processed. + * The callback function has to return true when it filled the buffer with samples or false when there is not enought data. + * On false the SOUND_object most probably will discard the buffer. Nevertheless it can try to call the callback again. + * \TODO revise the concept when the there will be a SOUND_object_t derivative that uses this approach. + * \note Needs addaptation of DSP::u::AudioOutput class. + */ + bool register_output_callback_object(DSP::u::AudioOutput *callback_object, output_callback_function &cp); + /*! \note If this function returns NULL, callbacks are not used are not used even if they are supported. + */ + DSP::u::AudioOutput *get_output_callback_object(); + protected: + bool output_callback_call(const DSP::e::SampleType &OutSampleType, const std::vector<char> &wave_out_raw_buffer); + + public: + SOUND_object_t(); + virtual ~SOUND_object_t(); + }; +} + + +#include <DSP_DOT.h> + +#endif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/WMM_support.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/WMM_support.h new file mode 100644 index 0000000000000000000000000000000000000000..63af56851b7b18e0dc00a4ef859afcee8db217c8 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/WMM_support.h @@ -0,0 +1,113 @@ +/*! \file WMM_support.h + * WMM support header file + * + * \author Marek Blok + */ +//--------------------------------------------------------------------------- +#ifndef WMM_support_H +#define WMM_support_H + +/* inluce WMM API */ +////#ifdef __CYGWIN__ +//#ifdef WIN32 +#if defined(WIN32) || defined(WIN64) + #include <windef.h> + #include <mmsystem.h> +#else + #error NO WIN32 +#endif + +#include <DSP_types.h> // for types + +namespace DSP { + class WMM_object_t : public DSP::SOUND_object_t { + private: + bool is_device_input_open; + bool is_device_output_open; + + HWAVEIN hWaveIn; + HWAVEOUT hWaveOut; + + MMRESULT result; + + //Rezerwacja pamiÄ™ci dla formatu WAVE + // WAVEFORMATEX wfx; //to wymaga korekty + PCMWAVEFORMAT wfx; + + unsigned int WaveOutDevNo; // device numer used in next open operations + + std::vector<WAVEHDR> waveHeaderOut; + uint32_t WaveOutBufferLen; // in bytes + //! Buffers for audio samples prepared for playing + std::vector<std::vector<uint8_t>> WaveOutBuffers; + //! Type of samples in WaveOutBuffers + DSP::e::SampleType OutSampleType; + //! Index of the buffer which must be used next time + unsigned long NextBufferOutInd; + + bool StopPlayback; + bool IsPlayingNow; + + static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, + uint32_t dwInstance, uint32_t dwParam1, uint32_t dwParam2); + + + unsigned int WaveInDevNo; // device numer used in next open operations + + //! Index of the buffer which is expected to filled next + short NextBufferInInd; + //! Type of samples in WaveInBuffers + DSP::e::SampleType InSampleType; + std::vector<WAVEHDR> waveHeaderIn; + uint32_t WaveInBufferLen; // in bytes + //! Buffers for audio samples prepared for playing + std::vector<std::vector<char>> WaveInBuffers; + + static void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, uint32_t dwInstance, uint32_t dwParam1, uint32_t dwParam2); + + bool StopRecording; + // indicates whether the recording started yet + bool IsRecordingNow; + + public: + + //! log basic WMM information + void log_driver_data(); + + // returns false if device is already opened + unsigned int select_input_device_by_number(const unsigned int &device_number=UINT_MAX); + unsigned int select_output_device_by_number(const unsigned int &device_number=UINT_MAX); + + //! opens default PCM device for playback and returns selected sampling rate on success or negative error code + long open_PCM_device_4_output(const int &no_of_channels, int no_of_bits, const long &sampling_rate, const long &audio_outbuffer_size = -1); + //! opens default PCM device for capture and returns selected sampling rate on success or negative error code + long open_PCM_device_4_input(const int &no_of_channels, int no_of_bits, const long &sampling_rate, const long &audio_inbuffer_size = -1); + + bool close_PCM_device_input(void); + bool close_PCM_device_output(void); + + bool stop_playback(void); + bool stop_recording(void); + //! returns true is the playback is on + bool is_device_playing(void); + //! returns true is the playback is on + bool is_device_recording(void); + + bool is_input_callback_supported(void); + bool is_output_callback_supported(void); + + //void get_params(snd_pcm_uframes_t &frames, unsigned int &period_time); + //snd_pcm_sframes_t pcm_writei(const void *buffer, snd_pcm_uframes_t &frames); + //! \note values stored in float_buffer might be altered + long append_playback_buffer(DSP::Float_vector &float_buffer); + bool start_recording(void); + bool get_wave_in_raw_buffer(DSP::e::SampleType &InSampleType, std::vector<char> &wave_in_raw_buffer); + + //! object constructor \TODO check use of virtual in constructor and destructor + WMM_object_t(); + ~WMM_object_t(); + }; + +} + +#endif // WMM_support_H diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/dbg/DSP_setup.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/dbg/DSP_setup.h new file mode 100644 index 0000000000000000000000000000000000000000..c18e34841efd1e755d66988319c3708b0326c6c4 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/dbg/DSP_setup.h @@ -0,0 +1,10 @@ +#ifndef DSP_Setup +#define DSP_Setup + + #define __DEBUG__ 1 + + //#define TestCompilation + //#define VerboseCompilation + //#define AUDIO_DEBUG_MESSAGES_ON + +#endif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/include/rls/DSP_setup.h b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/rls/DSP_setup.h new file mode 100644 index 0000000000000000000000000000000000000000..57255d2294b7e22e1c0617df7f880d5126d4e6d4 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/include/rls/DSP_setup.h @@ -0,0 +1,9 @@ +#ifndef DSP_Setup +#define DSP_Setup + + // #define __DEBUG__ 0 + + //#define TestCompilation + //#define VerboseCompilation + +#endif diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/rls/libDSPE.a b/DSPE_lib_minGW/MinGW-W64_8.1.0/rls/libDSPE.a new file mode 100644 index 0000000000000000000000000000000000000000..64df52b640070c013bda87da118d0efa9a0000d9 Binary files /dev/null and b/DSPE_lib_minGW/MinGW-W64_8.1.0/rls/libDSPE.a differ diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/rls/libDSPEsockets.a b/DSPE_lib_minGW/MinGW-W64_8.1.0/rls/libDSPEsockets.a new file mode 100644 index 0000000000000000000000000000000000000000..db4a109eff687018a3b86c6bf68e7bb1046b5c72 Binary files /dev/null and b/DSPE_lib_minGW/MinGW-W64_8.1.0/rls/libDSPEsockets.a differ diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/load_filter_coef.m b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/load_filter_coef.m new file mode 100644 index 0000000000000000000000000000000000000000..9a50c580b9b74b6afac97dafe9c9819d178ff105 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/load_filter_coef.m @@ -0,0 +1,107 @@ +function [coefficients, file_version] = load_filter_coef(filename) +% [coefficients, file_version] = load_filter_coef(filename) +% +% FIR filter coefficients +% coefficients.h +% - can be cell vector to store multiple FIR impulse responces +% For file_version >= 1 (default == 0), +% coefficients.Fp - sampling frequency +% +% This file is a part of Digital Signal Processing Engine +% \author Marek Blok +% \date 2008.03.28 + +% /*! File format (*.coef) - this is open format, for general use +% * (not only for storing coefficients) +% * +ind = find(filename == '.'); +if length(ind) == 0, + filename = [filename, '.coef']; +end +plik = fopen(filename, 'rb'); + +% * - (uchar) 1B - file version number +file_version = fread(plik, 1, 'uchar') + +switch file_version, + case 0, + case 1, + % * - (uint) 4B - Sampling frequency + coefficients.Fp = fread(plik, 1, 'uint32') + otherwise, + fclose(plik); + error('This version of coefficients file is unsupported'); +end + +% * - data - coefficients data (depends on fle version) +% * . +% * Data segment format: +% * -# (version: 0x00) +% * - (uchar) 1B - number of sample dimensions +% * 1 - real, 2 - complex, ... +no_of_channels = fread(plik, 1, 'uchar'); % complex +if no_of_channels == 1, + isComplex = 0; +elseif no_of_channels == 2, + isComplex = 1; +else + fclose(plik); + error('to many channels'); +end +% * - (uchar) 1B - sample component type +% * - DSP_FT_float (=1) : C++ float (32bit floating point) +% * - DSP_FT_short (=2) : C++ short (16bit signed integer) +% * - DSP_FT_uchar (=3) : C++ unsigned char (8bit unsigned integer with bias (0x80)) +% * - DSP_FT_double (=7) : C++ double (64bit floating point) +% * - DSP_FT_long_double (=8) : C++ long double (80bit floating point) +sample_type = fread(plik, 1, 'uchar'); +switch sample_type, + case 1, + sample_type = 'float'; + case 2, + sample_type = 'short'; + case 3, + sample_type = 'uchar'; + case 7, + sample_type = 'double'; + case 8, + sample_type = 'float80'; + otherwise + fclose(plik); + error('unknown sample type'); +end + +% * - (uchar) 1B - number of vectors +% * - 1 - FIR filter coefficients (one vector) +% * - 2 - IIR filter coefficients (two vectors) +% * - (x number of vectors) +% * - (ushort) 2B - number of samples in vector +% * - (x number of samples) +% * - (x number of sample dimensions) +% * - (sample componet type) xB - sample component +% * e.g. real, imag part +resp_no = fread(plik, 1, 'uchar'); + +if resp_no == 1, + N_FIR = fread(plik, 1, 'uint16'); + if isComplex, + dane = fread(plik, 2*N_FIR, sample_type); + coefficients.h = dane(1:2:2*N_FIR) + j*dane(2:2:2*N_FIR); + else + dane = fread(plik, N_FIR, sample_type); + coefficients.h = dane; + end +else + for ind_resp = 1:resp_no, + N_FIR = fread(plik, 1, 'uint16'); + if isComplex, + dane = fread(plik, 2*N_FIR, sample_type); + coefficients.h{ind_resp} = dane(1:2:2*N_FIR) + j*dane(2:2:2*N_FIR); + else + dane = fread(plik, N_FIR, sample_type); + coefficients.h{ind_resp} = dane; + end + end +end + +fclose(plik); diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/readaudiofile.m b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/readaudiofile.m new file mode 100644 index 0000000000000000000000000000000000000000..4fde7b0158c7eed49f1c295b345699e5663d471c --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/readaudiofile.m @@ -0,0 +1,218 @@ +function [x, Fs] = readaudiofile(filename, param) +% [x, Fs] = readaudiofile(filename, param) +% +% returns vector x of the size SIZE=[samples channels]. +% eg. x = x(:,1) + j*x(:,2); +% +% special uses: +% param == 'size': returns SIZE in x +% param == 'cplx': for stereo files returns x as a complex vector instead of matrix +% +% supported file types: +% *.flt +% *.wav +% *.tape +% last modification: 2021.04.10 +% Author: Marek Blok +if nargin == 0 + return +end + +return_cplx = 0; +if nargin == 1, + param = inf; +else + if strcmp(param, 'cplx') == 1, + return_cplx = 1; + param = inf; + end +end + +ind = find(filename == '.'); +if length(ind) == 0, + file_type = 'w'; % *.wav +else + ind = ind(end); + + temp = filename(ind+1:end); + + file_type = 'u'; % unknown format + if strcmp(temp, 'flt') == 1, + file_type = 'f'; % two channel floting point + elseif strcmp(temp, 'wav') == 1, + file_type = 'w'; % *.wav + elseif strcmp(temp, 'tape') == 1, + file_type = 't'; % *.tape + end +end + +switch file_type, + case 'w', + if strcmp(param, 'size') == 1, + if exist('audioread','file') == 0 + x = wavread(filename, 'size'); + % siz = [samples channels]. + else + info = audioinfo(filename); + x = [info.TotalSamples, info.NumChannels]; + Fs = info.SampleRate; + end + else + if isfinite(param) + if exist('audioread','file') == 0 + [x, Fs] = wavread(filename, param); + else + if length(param) == 1 + param = [1, param]; + end + [x, Fs] = audioread(filename, param); + end + else + if exist('audioread','file') == 0 + [x, Fs] = wavread(filename); + else + [x, Fs] = audioread(filename); + end + end + end + + case 't' + plik = fopen(filename, 'rb'); + if plik == -1, + error('File does not exist !!!'); + end + + header.size = fread(plik, 1, 'uint32', 0) + 4; + + header.fname = char(fread(plik, 256, 'char', 0).'); + header.cfg_fname = char(fread(plik, 256, 'char', 0).'); + header.sw_rev = fread(plik, 1, 'uint32', 0); + header.hw_rev = fread(plik, 1, 'uint32', 0); + header.file_ = fread(plik, 1, 'uint32', 0); + header.tape_type = fread(plik, 1, 'uint32', 0); + header.start_time = fread(plik, 1, 'int32', 0); % time_t + header.end_time = fread(plik, 1, 'int32', 0); % time_t + + header.total_samples = fread(plik, 1, 'uint32', 0); + file_length = header.total_samples * 4 + header.size + header.current_sample = fread(plik, 1, 'uint32', 0); + header.loop_start = fread(plik, 1, 'int64', 0); + header.loop_end = fread(plik, 1, 'int64', 0); + header.loop = fread(plik, 1, 'int32', 0); + header.group_size_32 = fread(plik, 1, 'uint32', 0); + header.block_size = fread(plik, 1, 'uint32', 0); + header.block_count = fread(plik, 1, 'uint32', 0); + header.fifo_size = fread(plik, 1, 'uint32', 0); + + + header.comment = char(fread(plik, 256, 'char', 0).'); + header.tmp = char(fread(plik, 20, 'char', 0).'); % time_t + header.status = fread(plik, 1, 'uint32', 0); + header.timestamps = fread(plik, 1, 'int32', 0); + header.freq = fread(plik, 1, 'float', 0); + header.cplx_datarate = fread(plik, 1, 'float', 0); + +% ftell(plik) + header.reserved = fread(plik, 128, 'uint32', 0); +% header.reserved.' + +% header +% ftell(plik) + + header.sample_type = 2; + header.ch_no = 2; + header.Fs = NaN; + + sample_type = 'int16'; + sample_size = 2; + + header_size = header.size; + if strcmp(param, 'size') == 1, + fseek(plik, 0, 'eof'); + size = (ftell(plik) - header_size) / sample_size / header.ch_no; % sizeof(float) *2 + x = [size, header.ch_no]; + else + fseek(plik, header_size, 'bof'); + + len = param(1); + if length(param) > 1, + fseek(plik, sample_size*header.ch_no*(param(1)-1), 'cof'); + len = param(2) - param(1) + 1; + end + +% x = fread(plik, [header.ch_no, len], sample_type); + x = fread(plik, [header.ch_no, len], sample_type, 0); + x = x.'; + end + fclose(plik); + + case 'f' + plik = fopen(filename, 'rb'); + if plik == -1, + error('File does not exist !!!'); + end + + % 3 B - wersja pliku (w tym typ próbek) + % 1 B - liczba kana³ów + % 4 B - szybkoœæ próbkowania + header_size = 8; + header.ver = fread(plik, 1, 'uint8'); + header.sample_type = fread(plik, 1, 'uint16'); + header.ch_no = fread(plik, 1, 'uint8'); + header.Fs = fread(plik, 1, 'uint32'); + + Fs = header.Fs; + + switch (header.ver), + case 0, + switch (header.sample_type), + case 0, + sample_type = 'float'; + sample_size = 4; + case 1, + sample_type = 'uchar'; + sample_size = 1; + case 2, + sample_type = 'short'; + sample_size = 2; + case 3, + sample_type = 'int'; + sample_size = 4; + otherwise + error('Unsupported *.flt sample type !!!'); + end + otherwise + error('Unsupported *.flt file version !!!'); + end + + + if strcmp(param, 'size') == 1, + fseek(plik, 0, 'eof'); + size = (ftell(plik) - header_size) / sample_size / header.ch_no; % sizeof(float) *2 + x = [size, header.ch_no]; + else + len = param(1); + status = 0; + if length(param) > 1, + status = fseek(plik, sample_size*header.ch_no*(param(1)-1), 'cof'); + len = param(2) - param(1) + 1; + end + + if (status == -1) + x = []; + else + x = fread(plik, [header.ch_no, len], sample_type); + x = x.'; + end + end + + fclose(plik); + otherwise + error('Unsupported file format !!!'); +end + +if return_cplx == 1, + if length(x(1,:)) == 2, + x = x(:,1) + j*x(:,2); + end +end diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/save_filter_coef.m b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/save_filter_coef.m new file mode 100644 index 0000000000000000000000000000000000000000..8cf1f072079de9ee5dab70dc9682ae0ae00ef1df --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/save_filter_coef.m @@ -0,0 +1,226 @@ +function save_filter_coef(filename, coefficients, file_version) +% save_filter_coef(filename, coefficients [, file_version]) +% +% FIR filter coefficients +% coefficients.h +% - can be cell vector to store multiple FIR impulse responces +% - if any of the impulse responses is complex then all responses will +% be stored as complex +% IIR filter coefficients +% coefficients.a +% coefficients.b +% +% For file_version >= 1 (default == 0), +% coefficients.Fp - sampling frequency +% +% This file is a part of Digital Signal Processing Engine +% +% File format (*.coef) - this is open format, for general use +% * (not only for storing coefficients) +% +% File format (*.h) - this is C++ header file for DSPElib with hardcoded *.coef equivalent +% +% \author Marek Blok +% \date 2020.02.22 + +if nargin == 2, + file_version = 0; +end + +ind = find(filename == '.'); +if length(ind) == 0, + filename = [filename, '.coef']; +end + +% detect mode based on file extention +[PATHSTR,NAME,EXT] = fileparts(filename); +switch EXT + case '.h' + mode = 'h-file'; + plik = fopen(filename, 'wt'); + + case '.coef' + mode = 'coefs-file'; + plik = fopen(filename, 'wb'); + + otherwise + mode = 'unknown-file'; + error(mode); +end + +switch mode + case 'h-file' + fprintf(plik, '// save_filter_coef output (hard coded coefficients)\n'); + fprintf(plik, '#pragma once\n'); + fprintf(plik, '#include <DSP_lib.h>\n'); + fprintf(plik, '\n'); + + if isfield(coefficients, 'h'), + h = coefficients.h; + + for ind_h = 0:length(h)-1 + fprintf(plik, 'DSP_float_vector Farrow_coefs_row_%i = {', ind_h); + h_tmp = h{ind_h+1}; + for ind_p = 0:length(h_tmp)-1, + if ind_p > 0 + fprintf(plik, ', '); + end + fprintf(plik, '%.15ff', h_tmp(ind_p+1)); + end + %0.1f, 0.2f, 0.1f + fprintf(plik, '};\n'); + end + fprintf(plik, '\n'); + + %vector <DSP_float_vector> Farrow_coefs = { coefs_0, coefs_1, coefs_2 }; + fprintf(plik, 'vector <DSP_float_vector> Farrow_coefs = {'); + for ind_h = 0:length(h)-1 + if ind_h > 0 + fprintf(plik, ', '); + end + if (ind_h < length(h_tmp)) & (rem(ind_h, 5) == 0) + fprintf(plik, '\n '); + end + fprintf(plik, 'Farrow_coefs_row_%i', ind_h); + end + fprintf(plik, '\n };\n'); + + fprintf(plik, '\n'); + fprintf(plik, 'const unsigned int p_Farrow = %i; // should be equal to Farrow_coefs[0].size()-1\n', length(h{1})-1); + fprintf(plik, 'const unsigned int N_FSD = %i; // should be equal to Farrow_coefs.size()\n', length(h)); + end + + if isfield(coefficients, 'b'), + fclose all; + error('unsupported: coefficients.b'); + end + if isfield(coefficients, 'a'), + fclose all; + error('unsupported: coefficients.a'); + end + + case 'coefs-file' + % * - (uchar) 1B - file version number + fwrite(plik, file_version, 'uchar'); + + switch file_version, + case 0, + case 1, + % * - (uint) 4B - Sampling frequency + if isfield(coefficients, 'Fp'), + fwrite(plik, coefficients.Fp, 'uint32'); + else + fclose(plik); + error('Input data does not contain Fp'); + end + otherwise, + fclose(plik); + error('This version of coefficients file is unsupported'); + end + + if isfield(coefficients, 'h'), + isFIR = 1; + if iscell(coefficients.h) + resp_no = length(coefficients.h); + % if resp_no = 1; + % coefficients.h = coefficients.h{1}; + % end + else + resp_no = 1; + end + if resp_no == 1, + isComplex = any(imag(coefficients.h(:))); + else + isComplex = false; + for ind_resp = 1:resp_no, + isComplex = isComplex | any(imag(coefficients.h{ind_resp}(:))); + end + end + else + isFIR = 0; + isComplex = any(imag(coefficients.a(:))) | any(imag(coefficients.b(:))); + end + + % * - data - coefficients data (depends on fle version) + % * . + % * Data segment format: + % * -# (version: 0x00) + % * - (uchar) 1B - number of sample dimensions + % * 1 - real, 2 - complex, ... + if isComplex, + fwrite(plik, 2, 'uchar'); % complex + else + fwrite(plik, 1, 'uchar'); % real + end + % * - (uchar) 1B - sample component type + % * - DSP_FT_float (=1) : C++ float (32bit floating point) + % * - DSP_FT_short (=2) : C++ short (16bit signed integer) + % * - DSP_FT_uchar (=3) : C++ unsigned char (8bit unsigned integer with bias (0x80)) + % * - DSP_FT_double (=7) : C++ double (64bit floating point) + % * - DSP_FT_long_double (=8) : C++ long double (80bit floating point) + fwrite(plik, 1, 'uchar'); + + % * - (uchar) 1B - number of vectors + % * - 1 - FIR filter coefficients (one vector) + % * - 2 - IIR filter coefficients (two vectors) + % * - (x number of vectors) + % * - (ushort) 2B - number of samples in vector + % * - (x number of samples) + % * - (x number of sample dimensions) + % * - (sample componet type) xB - sample component + % * e.g. real, imag part + if isFIR, + fwrite(plik, resp_no, 'uchar'); + + if iscell(coefficients.h) + for ind_resp = 1:resp_no, + N_FIR = length(coefficients.h{ind_resp}); + fwrite(plik, N_FIR, 'uint16'); + if isComplex, + dane(1:2:2*N_FIR) = real(coefficients.h{ind_resp}); + dane(2:2:2*N_FIR) = imag(coefficients.h{ind_resp}); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.h{ind_resp}), 'float'); + end + end + else + N_FIR = length(coefficients.h); + fwrite(plik, N_FIR, 'uint16'); + if isComplex, + dane(1:2:2*N_FIR) = real(coefficients.h); + dane(2:2:2*N_FIR) = imag(coefficients.h); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.h), 'float'); + end + end + + else + fwrite(plik, 2, 'uchar'); + + N_a = length(coefficients.a); + fwrite(plik, N_a, 'uint16'); + if isComplex, + dane(1:2:2*N_a) = real(coefficients.a); + dane(2:2:2*N_a) = imag(coefficients.a); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.a), 'float'); + end + + + N_b = length(coefficients.b); + fwrite(plik, N_b, 'uint16'); + if isComplex, + dane(1:2:2*N_b) = real(coefficients.b); + dane(2:2:2*N_b) = imag(coefficients.b); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.b), 'float'); + end + end + +end +fclose(plik); + diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/specgraf_2.m b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/specgraf_2.m new file mode 100644 index 0000000000000000000000000000000000000000..ec550aaeaea7ba268ede0200bdc9d0f03294adad --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/specgraf_2.m @@ -0,0 +1,1409 @@ +function varargout = specgraf_2(Akcja, param) +% Spectrogram for long signals +% +% last modification: 2013.12.04 +% Author: Marek Blok + +%cos(cumsum(n/1000)) + +% eval_specgram + +% audioplayer, audiorecorder !!! +% waitbar + +% \fixed 2005.11.20 dealt with "Warning: Log of zero." in ylim evaluation +% \fixed 2005.11.20 Placed all in single file +% \fixed 2005.11.20 Fixed problems with zoom out + +% \fixed 2013.07.05 Fixed obsolete finite +% \fixed 2013.07.06 Fixed zoom related warnings +% \added 2013.07.06 param.filename = 'name.wav'; specgraf_2('UserInit', param) +% + +% \added 2013.12.04 obs³ugê global specgram +% \added 2013.12.04 param.filename = 'name.wav'; +% param.out_dir = 'katalog'; +% specgraf_2('GetImage', param) +% \added 2013.12.04 przycisk 'Save image' +% \fixed 2021.03.29 Update to Matlab 2021a +ver_data = '2021.03.21'; + + +% fig = openfig(mfilename,'reuse'); return; %ZapiszFig(1,'specGUI.m') + if isempty(findobj(0, 'tag', 'Specgraf_DrawFig_2')) + + fig = Specgraf_DrawFig_2; + set(fig,'DoubleBuffer', 'on'); + set(fig,'tag', 'Specgraf_DrawFig_2', 'Units', 'pixels'); + set(fig,'name', ['Spektrogram d³ugich sygna³ów niestacjonarnych (', ver_data, ') dr in¿. Marek Blok'],... + 'KeyPressFcn','1;'); + + specgraf_2('Init'); + specgraf_2('signal'); + set(fig,'Visible','on'); +% specgraf_2('per'); + else + if nargin == 0 % close GUI + specgraf_2('Exit'); + end; + end + +if nargin == 0 % close GUI + return; +end + +if ~isstr(Akcja) % INVOKE NAMED SUBFUNCTION OR CALLBACK + disp('Something''s wrong'); + return; +end; + +% Generate a structure of handles to pass to callbacks, and store it. +fig=findobj(0, 'tag', 'Specgraf_DrawFig_2'); +hEdit_N=findobj(fig,'tag', 'N_edit'); +hEdit_filename=findobj(fig,'tag', 'filename_edit'); +hEdit_script=findobj(fig,'tag', 'script_edit'); +hEdit_L=findobj(fig,'tag', 'L_edit'); +hEdit_dF=findobj(fig,'tag', 'dF_edit'); +hEdit_k=findobj(fig,'tag', 'k_edit'); +hEdit_O=findobj(fig,'tag', 'O_edit'); +hEdit_Os=findobj(fig,'tag', 'Os_edit'); +hEdit_w=findobj(fig,'tag', 'w_edit'); +h_dB=findobj(fig,'tag', 'dB_checkbox'); +ha=get(fig, 'UserData'); +if length(ha) == 3, + ha_spec = ha(1); ha_per = ha(2); ha_time = ha(3); +else + ha_spec = []; ha_per = []; ha_time = []; +end +hEdit_dY=findobj(fig,'tag', 'dY_edit'); + +% przechowywania na potrzeby skoryzstania na zewn¹trz +global specgram + +if strcmp(Akcja, 'Exit') + close(fig); + return; + +elseif strcmp(Akcja, 'UserInit') + if nargin == 1, + warning('UserInit expects data in param'); + end +% specgraf_2('Init', param); + + set(hEdit_filename,'UserData',param.filename); + set(hEdit_filename,'String',param.filename); + set(hEdit_filename,'Max', 1); + + specgraf_2('signal'); + set(fig,'Visible','on'); + figure(fig); + +elseif strcmp(Akcja, 'Init') + if nargin == 1, + param.filename = 'test.wav'; + else + end + set(hEdit_filename,'UserData',param.filename); + set(hEdit_filename,'String',param.filename); + set(hEdit_filename,'Max', 1); + + set(hEdit_L,'UserData','-1'); + set(hEdit_L,'String','-1'); + + set(hEdit_dF,'UserData','10'); + set(hEdit_dF,'String','10'); + set(hEdit_k,'UserData','2'); + set(hEdit_k,'String','2'); + + set(hEdit_N,'UserData','4'); + set(hEdit_N,'String','4'); + set(hEdit_O,'UserData','50'); + set(hEdit_O,'String','50'); + + set(hEdit_w,'UserData','blackman(M)'); + set(hEdit_w,'String','blackman(M)'); + + set(hEdit_Os,'UserData','66'); + set(hEdit_Os,'String','66'); + + set(h_dB,'UserData',1); + set(h_dB,'Value',1); + + ha_spec=findobj(fig,'tag', 'spec_axes'); + ha_per=findobj(fig,'tag', 'per_axes'); + ha_time=findobj(fig,'tag', 'time_axes'); +% for ind=[1 2 4], axes(ha(ind)); zoom on; end; +% axes(ha_spec); zoom off; + + set(fig, 'UserData', [ha_spec, ha_per, ha_time]); + +% set(hMenu,'UserData', [NaN, NaN, NaN, NaN, NaN, NaN, NaN, 1, -100, 5, -100, 5]); %handles & maximal values + draw_params.hp_spec = NaN; + draw_params.hp_per = NaN; +% draw_params.hp_spec_slice = NaN; + draw_params.hp_spec_t2 = NaN; + draw_params.hp_per2 = NaN; + draw_params.min_spec = 0; + draw_params.max_spec = 1; + draw_params.min_per = 0; + draw_params.max_per = 1; + setappdata(fig, 'draw_params', draw_params); + + set(hEdit_dY,'String','80'); + return; + +elseif strcmp(Akcja, 'GetImage') + + try + param.out_dir + catch + tekst_filename=get(hEdit_filename,'UserData'); + ind=find(tekst_filename==0); + if ~isempty(ind) + tekst_filename=tekst_filename(1:ind(1)-1); + end; + + param.out_dir = 'figs\'; + param.filename = tekst_filename(1:end-4); + end + + pos = [1 6 [10 5]*4]; + set(fig, 'PaperPosition', pos); + to_file(fig, param.out_dir, param.filename, 3); + +elseif strcmp(Akcja, 'signal') + if nargin==2, + Ktory=param; + else + %save strings + tekst=[get(hEdit_L, 'String') 0]; + set(hEdit_L,'UserData', setstr(tekst)); + + tekst=[get(hEdit_filename, 'String') 0]; + set(hEdit_filename,'UserData', setstr(tekst)); + end; + + %generate signal + tekstL=get(hEdit_L,'UserData'); + ind=find(tekstL==0); + if ~isempty(ind) + tekstL=tekstL(1:ind(1)-1); + end; + eval(['L=' tekstL ';'], 'L=1;') + + n=0:L-1; + tekst_filename=get(hEdit_filename,'UserData'); + ind=find(tekst_filename==0); + if ~isempty(ind) + tekst_filename=tekst_filename(1:ind(1)-1); + end; + L_tmp = L; + if L_tmp <=0, L_tmp =1000; end; + +% if (L >=100*48000) | (L <= 0), L = 100*48000; end; +% L_tmp =1000000; + +% SIZ=WAVREAD(FILE,'size') + eval(['size_tmp = readaudiofile(''' tekst_filename ''', ''size'');'], 'size_tmp = -1;'); + if (size_tmp ~= -1) & (max(size_tmp) < L), + L = max(size_tmp); + elseif L <= 0, + L = max(size_tmp); + end + eval(['[x, Fs]=readaudiofile(''' tekst_filename ''', L);'], 'x=randn(1,L_tmp); L = L_tmp; Fs=48000;') + +% size(x,1) + if size(x,2) == 2, + x = x(:,1) + j*x(:,2); + end + + x=x(:); + if L <= 0, L = length(x); end; + if length(x)<L; + x(L)=0; + else + x=x(1:L); + end; + + setappdata(fig, 'signal', x); + setappdata(fig, 'Fs', Fs); +% max_x(Ktory)=max(abs([real(x); imag(x)])); + + %draw signal + draw_params = getappdata(fig, 'draw_params'); + if ishandle(draw_params.hp_spec), + delete(draw_params.hp_spec); + draw_params.hp_spec = NaN; + end + if ishandle(draw_params.hp_spec_t2), + delete(draw_params.hp_spec_t2); + draw_params.hp_spec_t2 = NaN; + end + if ishandle(draw_params.hp_per), + delete(draw_params.hp_per); + draw_params.hp_per = NaN; + end +% if ishandle(draw_params.hp_spec_slice), +% delete(draw_params.hp_spec_slice); +% draw_params.hp_spec_slice = NaN; +% end + if ishandle(draw_params.hp_per2), + delete(draw_params.hp_per2); + draw_params.hp_per2 = NaN; + end + draw_params.min_spec = 0; + draw_params.max_spec = 1; + draw_params.min_per = 0; + draw_params.max_per = 1; + setappdata(fig, 'draw_params', draw_params); + + %compute and draw periodogram + specgraf_2('spec') +% specgraf_2 zoom_on; + return; + +elseif strcmp(Akcja, 'spec') + if nargin==2, + Ktory=param; + else + %save strings + tekst=[get(hEdit_dF, 'String') 0]; + set(hEdit_dF,'UserData', setstr(tekst)); + tekst=[get(hEdit_k, 'String') 0]; + set(hEdit_k,'UserData', setstr(tekst)); + + tekst=[get(hEdit_N, 'String') 0]; + set(hEdit_N,'UserData', setstr(tekst)); + tekst=[get(hEdit_O, 'String') 0]; + set(hEdit_O,'UserData', setstr(tekst)); + tekst=[get(hEdit_w, 'String') 0]; + set(hEdit_w,'UserData', setstr(tekst)); + + tekst=[get(hEdit_Os, 'String') 0]; + set(hEdit_Os,'UserData', setstr(tekst)); + end; + + %get signal + x=getappdata(fig, 'signal'); + Fs=getappdata(fig, 'Fs'); + draw_params=getappdata(fig, 'draw_params'); + + + tekst_k=get(hEdit_k,'UserData'); + ind=find(tekst_k==0); + if ~isempty(ind) + tekst_k=tekst_k(1:ind(1)-1); + end; + eval(['k=' tekst_k ';'], 'k=1;') + + tekst_dF=get(hEdit_dF,'UserData'); + ind=find(tekst_dF==0); + if ~isempty(ind) + tekst_dF=tekst_dF(1:ind(1)-1); + end; + eval(['dF=' tekst_dF ';'], 'dF=1;') + + % wielkoœæ segmentu do obliczania periodografu + % oraz wielkoœæ transformaty DFT + M = 2.^(ceil(log2(ceil(Fs/dF)))); + K = M*k; + + tekst_N=get(hEdit_N,'UserData'); + ind=find(tekst_N==0); + if ~isempty(ind) + tekst_N=tekst_N(1:ind(1)-1); + end; + eval(['N=' tekst_N ';'], 'N=1;') +% if M>K +% M=K; +% set(hEditM,'String', num2str(M)); +% end; + + tekstO=get(hEdit_O,'UserData'); + ind=find(tekstO==0); + if ~isempty(ind) + tekstO=tekstO(1:ind(1)-1); + end; +% eval(['O=' tekstO ';'], 'O=0;') + O=eval(tekstO, '0'); % \Fixed 2005.11.03 + O=round(O/100*M); % \Fixed 2005.11.03 nak³adkowanie podawane w procentach !!! + + tekstOs=get(hEdit_Os,'UserData'); + ind=find(tekstOs==0); + if ~isempty(ind) + tekstOs=tekstOs(1:ind(1)-1); + end; + Os=eval(tekstOs, '0'); + M_segment = N*M-(N-1)*O; + Os=round(Os/100*M_segment); % \Fixed 2005.11.03 nak³adkowanie podawane w procentach !!! + + tekstW=get(hEdit_w,'UserData'); + ind=find(tekstW==0); + if ~isempty(ind) + tekstW=tekstW(1:ind(1)-1); + end; + eval(['w=' tekstW ';'], 'w=ones(1,M);') + + w=w(:); + if length(w)<M; + w(M)=0; + else + w=w(1:M); + end; + +% x=get(hp_re(Ktory), 'Ydata')+j*get(hp_im(Ktory), 'Ydata'); + +% O=floor(O/100*M); % \Fixed 2005.11.03 + if O>=M + O=M-1; + set(hEdit_O,'String', num2str(O/M*100)); + end; +% N = fix((length(x)-O)/(M-O)); +% set(hEditN, 'String', sprintf('%i', N)); + +% [Spec, f, t]=specgram(x, K, 1, w, O); +% Spec=(abs(Spec).^2)/norm(w)^2; + [specgram.Spec, specgram.f, specgram.t, specgram.Per]=eval_specgram(x, K, Fs, w, O, N, Os); + [specgram.t_Ex, specgram.Ex] = eval_energy(x, O, Fs); + specgram.f2 = specgram.f; +% [Per, f2]=psd(x, K, 1, w, O); +% Per=abs(Per); + + + setappdata(fig, 'f',specgram.f); % set(get(ha(2),'Ylabel'),'UserData', f); + setappdata(fig, 'Spec',specgram.Spec); % set(get(ha_spec,'Ylabel'),'UserData', Spec); + setappdata(fig, 'Per',specgram.Per); % set(get(ha_per,'Ylabel'),'UserData', Per); + +% draw_params.min_spec=min([min(Spec(finite(Spec))); 0]); +% draw_params.max_spec=max([max(Spec(finite(Spec))); 0.001]); +% draw_params.min_per=min([min(Per(finite(Per))); 0]); +% draw_params.max_per=max([max(Per(finite(Per))); 0.001]); + draw_params.min_spec=min([min(specgram.Spec(isfinite(specgram.Spec))); 0]); + draw_params.max_spec=max([max(specgram.Spec(isfinite(specgram.Spec))); draw_params.min_spec+0.001]); + draw_params.min_per=min([min(specgram.Per(isfinite(specgram.Per))); 0]); + draw_params.max_per=max([max(specgram.Per(isfinite(specgram.Per))); draw_params.min_per+0.001]); + if get(h_dB, 'UserData') %dB + specgram.Spec=10*log10(specgram.Spec); + specgram.Per=10*log10(specgram.Per); + end + + %spektrogram + if length(specgram.t)>1 + specgram.t2=specgram.t+(specgram.t(2)-specgram.t(1))/2; + else + specgram.t2=M/2*(1/Fs); + specgram.t=specgram.t2; + end; + + axes(ha_spec); + if ~ishandle(draw_params.hp_spec) + hold on; + draw_params.hp_spec=image(specgram.t2, specgram.f, specgram.Spec); + set(draw_params.hp_spec, 'CDataMapping', 'scaled'); + colormap(hot); + hold off; + else + set(draw_params.hp_spec,'Xdata', specgram.t2, 'Ydata', specgram.f, 'Cdata', specgram.Spec); + end + if length(specgram.t)==1, + tlim_=[specgram.t(1)-0.5 specgram.t(1)+0.5]; + else + tlim_=[specgram.t(1) specgram.t(length(specgram.t))+specgram.t(2)-specgram.t(1)]; + end; + if isreal(x) + set(ha_spec, 'Ylim', [0 Fs/2], 'Xlim', tlim_); + else + set(ha_spec, 'Ylim', [-Fs/2 Fs/2], 'Xlim', tlim_); + end + eval('zoom reset', 'set(get(draw_params.ha_spec,''ZLabel''),''UserData'',[]);'); + + axes(ha_time); + plot(specgram.t_Ex, specgram.Ex, 'k'); + set(ha_time, 'Xlim', tlim_); +% set(get(ha_spec,'ZLabel'),'UserData',[]); +% reset(get(ha_spec,'ZLabel')); + + axes(ha_per); + if ~ishandle(draw_params.hp_per) + hold on; + draw_params.hp_per=plot(specgram.f2, specgram.Per, 'Color', 'k'); + hold off; + else + set(draw_params.hp_per,'Xdata', specgram.f2, 'Ydata', specgram.Per, 'Color', 'k'); + end +% set(ha_per, 'Xdir', 'reverse', 'YTick', []); %, 'Xlim', [t(1) t(length(t))], 'Ylim', [-1.1 1.1]*max(max_x)); + if isreal(x), + set(ha_per, 'Xlim', [0 Fs/2]); + else + set(ha_per, 'Xlim', [-Fs/2 Fs/2]); + end + eval('rmappdata(get(draw_params.ha_per,''Zlabel''),''ZOOMAxesData'')','set(get(ha_per,''ZLabel''),''UserData'',[])'); + +% set(hMenu,'UserData', [hp_re, hp_im, hp_spec_t, hp_spec_t2, hp_spec, hp_per, hp_per2, max_x, min_spec, max_spec, min_per, max_per]); + setappdata(fig, 'draw_params', draw_params); + +% % delete +% if 1 +% if isfinite(draw_params.hp_spec_slice), +% delete(draw_params.hp_spec_slice) +% draw_params.hp_spec_slice=NaN; +% setappdata(fig, 'draw_params', draw_params); +% end; +% end + + specgraf_2('spec_ylim'); + specgraf_2 zoom_on; + specgraf_2 zoom_off; + return; + +elseif strcmp(Akcja, 'dB') + pom=get(h_dB, 'UserData'); + if pom~=get(h_dB, 'Value') +% sygn=getappdata(fig, 'signal'); + Fs=getappdata(fig, 'Fs'); + f=getappdata(fig, 'f'); + per=getappdata(fig, 'Per'); + Spec=getappdata(fig, 'Spec'); + draw_params = getappdata(fig, 'draw_params'); + + if get(h_dB, 'Value') %dB +% sygn=10*log10(sygn); + per=10*log10(per); + Spec=10*log10(Spec); +% else %lin +% % sygn=10.^(sygn/10); +% per=10.^(per/10); + end; +% setappdata(fig, 'Per', per); + set(h_dB, 'UserData', get(h_dB, 'Value')); + + if ishandle(draw_params.hp_per2), + delete(draw_params.hp_per2); + draw_params.hp_per2 = NaN; + end + setappdata(fig, 'draw_params', draw_params); + + set(draw_params.hp_spec,'Cdata', Spec); + set(draw_params.hp_per,'Xdata', f, 'Ydata', per); + + specgraf_2('spec_ylim'); + end + return + +elseif strcmp(Akcja, 'spec_ylim') + draw_params=getappdata(fig, 'draw_params'); +% pom=get(hMenu,'UserData'); +% hp_re=pom(:,1); +% hp_im=pom(:,2); +% hp_spec_t=pom(:,3); +% hp_spec=pom(:,5); +% hp_per=pom(:,6); +% min_spec=pom(:,9); +% max_spec=pom(:,10); +% min_per=pom(:,11); +% max_per=pom(:,12); + if get(h_dB, 'UserData') %dB + tekst=get(hEdit_dY,'String'); + eval(['dY=' tekst ';'], 'dY=80;'); + if dY<=0, dY=10; end; + params_=[min(draw_params.min_spec) max(draw_params.max_spec)]; + ind_params = find(abs(params_) <= eps); + if length(ind_params) > 0, + params_(ind_params) = NaN*ones(size(ind_params)); + end + ylim_=10*log10(params_); + if ~isfinite(ylim_(2)) + ylim_(2)=0; + end + ylim_(1)=ylim_(2)-dY; + params_=[min(draw_params.min_per) max(draw_params.max_per)]; + ind_params = find(abs(params_) <= eps); + if length(ind_params) > 0, + params_(ind_params) = NaN*ones(size(ind_params)); + end + ylim_per=10*log10(params_); + if ~isfinite(ylim_per(2)) + ylim_per(2)=0; + end + ylim_per(1)=ylim_per(2)-dY; + else + ylim_=[0 max(draw_params.max_spec)]; + ylim_per=[0 max(draw_params.max_per)]; + end + ylim_per(2)=max([ylim_per(2) ylim_(2)]); +% f=getappdata(fig, 'f'); %get(get(ha(2),'Ylabel'),'UserData'); +% Spec=getappdata(fig, 'Spec'); %get(get(ha_spec,'Ylabel'),'UserData'); +% Per=getappdata(fig, 'Per'); %get(get(ha_per,'Ylabel'),'UserData'); +% Spec=64*(Spec-ylim_(1))/(ylim_(2)-ylim_(1)); +% % colormap(hot) + +% set(draw_params.hp_spec,'Cdata', Spec); + set(ha_spec,'Clim', ylim_per); +% set(draw_params.hp_per,'Xdata', f, 'Ydata', Per); + set(ha_per,'Ylim', ylim_per); +% set(ha_time,'Ylim', ylim_per); + +% if get(h_dB, 'UserData') %dB +% set(hp_spec_t(Ktory),'Ydata', 20*log10(abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata')))); +% else +% set(hp_spec_t(Ktory),'Ydata', abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata'))); +% end + + specgraf_2 zoom_on; + eval('zoom reset', 'set(get(ha_spec,''ZLabel''),''UserData'',[]);'); + specgraf_2 zoom_off; + return +elseif strcmp(Akcja, 'zoom_on') + h_zoom = zoom(fig); + set(h_zoom,'ActionPreCallback',@myprecallback); + set(h_zoom,'ActionPostCallback',@mypostcallback); + set(h_zoom,'Enable','on'); +% +% zoom on; +% pom=get(fig, 'WindowButtonDownFcn'); +% set(fig, 'WindowButtonDownFcn', 'specgraf_2 zoom'); +% set(get(ha_spec,'Xlabel'), 'UserData', pom); + return; +elseif strcmp(Akcja, 'zoom_off') + if get(findobj(fig,'tag','checkbox_zoom'),'Value') == 0, +% pom = get(get(ha_spec,'Xlabel'), 'UserData'); +% set(fig, 'WindowButtonDownFcn', pom); + h_zoom = zoom(fig); + set(h_zoom,'Enable','off'); +% zoom off; + set(fig, 'WindowButtonDownFcn', 'specgraf_2 zoom'); + set(get(ha_spec,'Xlabel'), 'UserData', '1;'); + end + return; +elseif strcmp(Akcja, 'zoom_spec') + if get(findobj(fig,'tag','checkbox_zoom'),'Value') ~= 0, + specgraf_2 zoom_on; + else + specgraf_2 zoom_off; + end +elseif strcmp(Akcja, 'zoom') +% if strcmp(get(fig,'SelectionType'),'normal') | (gca~=ha_spec) + pause(0); + if (get(gco,'Parent')~=ha_spec) | get(findobj(fig,'tag','checkbox_zoom'),'Value') + eval(get(get(ha_spec,'Xlabel'), 'UserData')); + elseif get(gco,'Parent')==ha_spec + pom=get(ha_spec, 'CurrentPoint'); + f_=pom(1,2); t_=pom(1,1); + + draw_params = getappdata(fig, 'draw_params'); +% f=get(draw_params.hp_spec, 'Ydata'); + f=getappdata(fig, 'f'); + ind_f=find(abs(f-f_)==min(abs(f-f_))); ind_f=ind_f(1); + t=get(draw_params.hp_spec, 'Xdata'); +% if length(t)>1, +% t=t+(t(2)-t(1))/2; +% end; + ind_t=find(abs(t-t_)==min(abs(t-t_))); + ind_t=ind_t(1); + set(findobj(fig,'tag', 'text_t_f'),... + 'ForegroundColor', 'r', 'String', sprintf('n=%i, f=%6.3f', t(ind_t),f(ind_f))); + + Spec=getappdata(fig, 'Spec'); + if length(Spec(:,ind_t))>length(f) + ind=find(f==0); + Spec(ind(1),:)=[]; + end; + if get(h_dB, 'Value') %dB + axes(ha_per); + if ~ishandle(draw_params.hp_per2) + hold on; +% draw_params.hp_per2=plot(f, 10*log10(Spec(:,ind_t)), 'Color', 'r', 'LineWidth', 2); + draw_params.hp_per2=plot(f, 10*log10(Spec(:,ind_t)), 'Color', 'r', 'LineWidth', 1); + hold off; + else + set(draw_params.hp_per2,'Xdata', f, 'Ydata', 10*log10(Spec(:,ind_t))); + end + axes(ha_time); + if ~ishandle(draw_params.hp_spec_t2) + hold on; + draw_params.hp_spec_t2=plot(t, 10*log10(Spec(ind_f,:)), 'Color', 'b', 'LineWidth', 1); + hold off; + else + set(draw_params.hp_spec_t2,'Xdata', t, 'Ydata', 10*log10(Spec(ind_f,:))); + end + else + axes(ha_per); + if ~ishandle(draw_params.hp_per2) + hold on; + draw_params.hp_per2=plot(f, Spec(:,ind_t), 'Color', 'r', 'LineWidth', 2); + hold off; + else + set(draw_params.hp_per2,'Xdata', f, 'Ydata', Spec(:,ind_t)); + end + axes(ha_time); + if ~ishandle(draw_params.hp_spec_t2) + hold on; + draw_params.hp_spec_t2=plot(t, Spec(ind_f,:), 'Color', 'b', 'LineWidth', 1); + hold off; + else + set(draw_params.hp_spec_t2,'Xdata', t, 'Ydata', Spec(ind_f,:)); + end + end; + + setappdata(fig, 'draw_params', draw_params); + end; + return; +end; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [Spec, f, t, Per]=eval_specgram_1(x, K, Fs, w, O, N, Os) +global spegraf_progress_stop; +spegraf_progress_stop=0; +hb=waitbar(0,'Spectrogram evaluation in progress','CreateCancelBtn','global spegraf_progress_stop; spegraf_progress_stop=1;'); + +try + L=length(x); + M=length(w); + % M próbek -> okienkowanie -> fft o d³ugoœci K + % przesuñ o (M - O) i tak N razy + % pocz¹tki segmentów: 1, 1+(M-O) = M-O+1, 1+2*(M-O) = 2*M-2*O+1, ... , 1+(N-1)*(M-O) = (N-1)*M-(N-1)*O+1 + % koñce segmentów: M, M+(M-O) = 2*M-O, M+2*(M-O) = 3*M-2*O, ... , M+(N-1)*(M-O) = N*M-(N-1)*O + M_segment = N*M-(N-1)*O; + + if L < M_segment, + x(M_segment) = 0; + L = M_segment; + end + + Spec=[]; t = []; Per = 0; + start = 1; koniec = M_segment; + ile = 0; w_skala = norm(w)^2; + while koniec <= L, + % x_ = x(start:koniec).*w; + t=[t, ((start+koniec)/2-1)/Fs]; + + X = 0; + for ind=0:N-1, + x_ = x(start+(ind)*(M-O)+[0:M-1]); + x_ = x_(:).*w(:); + X_ = fft(x_, K); + + if isreal(x), + X_ = abs(X_(1:end/2+1)); + else + X_ = fftshift(abs(X_)); + end + X_ = (X_.^2)/M/w_skala; +% Spec=(abs(Spec).^2)/norm(w)^2; + + X=X+X_; + end + X = X/N; + Spec(:,end+1)=X(:); + Per=Per+X; + ile = ile + 1; + + start = start + (M_segment - Os); + koniec = koniec + (M_segment - Os); + waitbar(koniec/L, hb); + if spegraf_progress_stop == 1, + break; + end + end + Per=Per/ile; + + if isreal(x), + f = linspace(0, Fs/2, K/2+1); + else + f = linspace(-Fs/2, Fs/2, K+1); + f(end) = []; + end +catch + test = 0; +end +delete(hb); +clear global spegraf_progress_stop; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [Spec, f, t, Per]=eval_specgram(x, K, Fs, w, O, N, Os) +global spegraf_progress_stop; +spegraf_progress_stop=0; +hb=waitbar(0,'Spectrogram evaluation in progress','CreateCancelBtn','global spegraf_progress_stop; spegraf_progress_stop=1;'); + +try + L=length(x); + M=length(w); + + offset_ = round(Os/M); + if offset_ <= 0, offset = 1; end; + if offset_ > N, offset = N; end; + + % M próbek -> okienkowanie -> fft o d³ugoœci K + % przesuñ o (M - O) i tak N razy + % pocz¹tki segmentów: 1, 1+(M-O) = M-O+1, 1+2*(M-O) = 2*M-2*O+1, ... , 1+(N-1)*(M-O) = (N-1)*M-(N-1)*O+1 + % koñce segmentów: M, M+(M-O) = 2*M-O, M+2*(M-O) = 3*M-2*O, ... , M+(N-1)*(M-O) = N*M-(N-1)*O + M_segment = N*M-(N-1)*O; + + if L < M_segment, + x(M_segment) = 0; + L = M_segment; + end + + Per = 0; + start = 1; koniec = M; + ile = 0; +% w_skala = norm(w)^2 + w_skala = mean(w.^2); + if isreal(x), + temp_X = zeros(K/2+1, N); ind = N; + ile_tmp=ceil((L-M_segment+(M-O))/((M-O)*offset_)); + Spec = zeros(K/2+1, ile_tmp); t = zeros(1, ile_tmp); + else + temp_X = zeros(K, N); ind = N; + ile_tmp=ceil((L-M_segment+(M-O))/((M-O)*offset_)); + Spec = zeros(K, ile_tmp); t = zeros(1, ile_tmp); + end + segment_ind_tmp = 1; + while koniec <= L, + % x_ = x(start:koniec).*w; +% t=[t, ((start+koniec)/2-1)/Fs]; + + + x_ = x(start+[0:M-1]); + x_ = x_(:).*w(:); + X_ = fft(x_, K); + if isreal(x), + X_ = abs(X_(1:end/2+1)); + else + X_ = fftshift(abs(X_)); + end + +% temp_X(:,ind) = (X_.^2)/M/w_skala; + temp_X(:,segment_ind_tmp) = (X_.^2)/M/w_skala; + segment_ind_tmp = rem(segment_ind_tmp, N) + 1; + + ind = ind -1; + if ind == 0, + X = 0; + for ind_=1:N, + X=X+temp_X(:,ind_); + end + X = X/N; + +% for ind_=offset_:N-1, +% temp_X(:,ind_+1) = temp_X(:,ind_); +% end + +% Spec(:,end+1)=X(:); + t(ile+1)=((start+koniec)/2-1)/Fs; + Spec(:,ile+1)=X(:); + Per=Per+X; + ile = ile + 1; + + ind = offset_; + end + + start = start + (M-O); + koniec = koniec + (M-O); + waitbar(koniec/L, hb); + if spegraf_progress_stop == 1, + break; + end + end + Per=Per/ile; + if ile < ile_tmp, + Spec = Spec(:, 1:ile); + t = t(1:ile); + end + + if isreal(x), + f = linspace(0, Fs/2, K/2+1); + else + f = linspace(-Fs/2, Fs/2, K+1); + f(end) = []; + end +catch + test = 0; +end +delete(hb); +clear global spegraf_progress_stop; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [t_Ex, Ex] = eval_energy(x, O, Fs) + +if O > length(x) + O = length(x); +end +dt = O/Fs; +wind = blackman(O); wind = wind / sum(wind); + +Ex_len = floor(length(x)/O); +Ex = zeros(Ex_len,1); +t_Ex = dt/2 + (0:Ex_len-1)*dt; + +E = abs(x(:)).^2; +for ind =1:O, +% tmp = wind(ind)*E(ind:O:Ex_len*O); + Ex = Ex + wind(ind)*E(ind:O:Ex_len*O); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function fig_h=Specgraf_DrawFig_2 +fig_h=figure; +set(fig_h, ... + 'Units', 'Normalized',... + 'Position', [0.1047 0.1146 0.7813 0.7448],... + 'Color', [1.0000 1.0000 1.0000],... + 'Name', 'Untitled',... + 'NumberTitle', 'off',... + 'Menu', 'none',... + 'Tag', 'figure1'... + ); +h=axes; +set(h, ... + 'Units', 'Normalized',... + 'Position', [0.0330 0.5203 0.9540 0.1413],... + 'Color', [1.0000 1.0000 1.0000],... + 'XColor', [0.0000 0.0000 0.0000],... + 'YColor', [0.0000 0.0000 0.0000],... + 'FontSize', 10,... + 'Box', 'on',... + 'Tag', 'time_axes'... + ); +h=axes; +set(h, ... + 'Units', 'Normalized',... + 'Position', [0.5490 0.7175 0.4400 0.2769],... + 'Color', [1.0000 1.0000 1.0000],... + 'XColor', [0.0000 0.0000 0.0000],... + 'YColor', [0.0000 0.0000 0.0000],... + 'FontSize', 10,... + 'Box', 'on',... + 'Tag', 'per_axes'... + ); +h=axes; +set(h, ... + 'Units', 'Normalized',... + 'Position', [0.0330 0.0825 0.9550 0.3846],... + 'Color', [1.0000 1.0000 1.0000],... + 'XColor', [0.0000 0.0000 0.0000],... + 'YColor', [0.0000 0.0000 0.0000],... + 'FontSize', 10,... + 'Box', 'on',... + 'Tag', 'spec_axes'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'frame',... + 'Units', 'Normalized',... + 'Position', [0.0050 0.7483 0.2450 0.2420],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', '',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'frame2'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'frame',... + 'Units', 'Normalized',... + 'Position', [0.2550 0.7497 0.2450 0.2406],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', '',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'frame4'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.4480 0.9217 0.0370 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2(''spec'')',... + 'Tag', 'k_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.4140 0.9273 0.0310 0.0252],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'k =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text25'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +% set(h, ... +% 'Style', 'edit',... +% 'Units', 'Normalized',... +% 'Position', [0.0180 0.8140 0.2210 0.0364],... +% 'BackGroundColor', [1.0000 1.0000 1.0000],... +% 'String', 'Edit Text',... +% 'Value', 0,... +% 'Visible', 'on',... +% 'Callback', 'specgraf_2(''signal'')',... +% 'Tag', 'prescript_edit'... +% ); +% h=uicontrol; +% x=version; +% if (x(1)>='5'), +% set(h, ... +% 'FontSize', 10); +% end; +% set(h, ... +% 'Style', 'text',... +% 'Units', 'Normalized',... +% 'Position', [0.0120 0.8503 0.1380 0.0280],... +% 'BackGroundColor', [0.9255 0.9137 0.8471],... +% 'String', 'preprocessing script =',... +% 'Value', 0,... +% 'Visible', 'on',... +% 'Callback', '',... +% 'Tag', 'text24'... +% ); +% h=uicontrol; +% x=version; +% if (x(1)>='5'), +% set(h, ... +% 'FontSize', 10); +% end; +set(h, ... + 'Style', 'pushbutton',... + 'Units', 'Normalized',... + 'Position', [0.0110 0.7035 0.1180 0.0378],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Refresh',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2 Refresh',... + 'Tag', 'pushbutton6'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'checkbox',... + 'Units', 'Normalized',... + 'Position', [0.8720 0.0126 0.0660 0.0196],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'zoom',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2 zoom_spec',... + 'Tag', 'checkbox_zoom'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'pushbutton',... + 'Units', 'Normalized',... + 'Position', [0.0140 0.0098 0.0660 0.0378],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Exit',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2 Exit',... + 'Tag', 'pushbutton5'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'pushbutton',... + 'Units', 'Normalized',... + 'Position', [0.2540 0.0098 0.0660 0.0378],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Save image',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2 GetImage',... + 'Tag', 'pushbutton5'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.4640 0.0028 0.3540 0.0350],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', '',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text_t_f'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.1750 0.0126 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2(''spec_ylim'')',... + 'Tag', 'dY_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.1110 0.0154 0.0620 0.0308],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'dY [dB] =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text21'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'checkbox',... + 'Units', 'Normalized',... + 'Position', [0.4480 0.7091 0.0500 0.0322],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'dB',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2(''dB'')',... + 'Tag', 'dB_checkbox'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.2930 0.8643 0.0570 0.0406],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2(''spec'')',... + 'Tag', 'N_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.2630 0.8741 0.0300 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'N =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text18'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0470 0.7608 0.1110 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2(''signal'')',... + 'Tag', 'L_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0170 0.7636 0.0290 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'L =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text17'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.4130 0.8685 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2(''spec'')',... + 'Tag', 'O_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.3600 0.8699 0.0500 0.0280],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'O [%] =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text16'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.3010 0.8196 0.1870 0.0336],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2(''spec'')',... + 'Tag', 'w_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.2600 0.8210 0.0400 0.0294],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'w[n] =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text15'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.3240 0.7692 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2(''spec'')',... + 'Tag', 'Os_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.2620 0.7706 0.0530 0.0308],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Os [%] =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text13'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.2600 0.9622 0.1470 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Spectrograph parameters',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text10'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.3250 0.9231 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2(''spec'')',... + 'Tag', 'dF_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.2640 0.9273 0.0550 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'dF [Hz] =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text9'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0190 0.8923 0.2210 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'specgraf_2(''signal'')',... + 'Tag', 'filename_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0130 0.9287 0.0990 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'wave filename =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text4'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0120 0.9636 0.1010 0.0238],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Testing signal',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text2'... + ); + + +function myprecallback(obj,evd) +% disp('A zoom is about to occur.'); +% specgraf_2 zoom + +function mypostcallback(obj,evd) +% newLim = get(evd.Axes,'XLim'); +% msgbox(sprintf('The new X-Limits are [%.2f %.2f].',newLim)); diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/writeaudiofile.m b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/writeaudiofile.m new file mode 100644 index 0000000000000000000000000000000000000000..7c5a5944bed6f25a3a0df314d5cb41ce16481166 --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/writeaudiofile.m @@ -0,0 +1,86 @@ +function writeaudiofile(filename, x, sample_type, Fs) + +if nargin == 2, + sample_type = 'float'; + Fs= NaN; +elseif nargin == 3, + Fs= NaN; +end + +ind = find(filename == '.'); +if length(ind) == 0, + filename = [filename, '.flt']; +end + +plik = fopen(filename, 'wb'); +if plik == -1, + error +end + +% 3 B - wersja pliku (w tym typ próbek) +% 1 B - liczba kana³ów +% 4 B - szybkoœæ próbkowania + +header.ver = 0; +switch (sample_type), + case 'float'; + header.sample_size = 4; + header.sample_type = 0; + case 'uchar'; + header.sample_size = 1; + header.sample_type = 1; + case 'short'; + header.sample_size = 2; + header.sample_type = 2; + case 'int'; + header.sample_size = 4; + header.sample_type = 3; + otherwise + error('Unsupported *.flt sample type !!!'); +end +pom = size(x); +if min(pom) == 0, + error('empty data !!!'); +elseif min(pom) == 1, + header.ch_no = 1; + x = x(:).'; + if any(imag(x) ~= 0), + header.ch_no = 2; + x_ = zeros(1, header.ch_no*length(x)); + x_(1:header.ch_no:end) = real(x); + x_(2:header.ch_no:end) = imag(x); + x = x_; clear x_; + end +elseif pom(1) < pom(2) + header.ch_no = pom(1); + x_ = zeros(1, pom(1)*pom(2)); + for ind=1:header.ch_no, + x_(ind:header.ch_no:end) = x(ind, :); + end + x = x_; clear x_; +else + header.ch_no = pom(2); + + x_ = zeros(1, pom(1)*pom(2)); + for ind=1:header.ch_no, + x_(ind:header.ch_no:end) = x(:, ind); + end + x = x_; clear x_; +end +size(x) + +if ~isfinite(Fs), + header.Fs = 0; +else + header.Fs = Fs; +end; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% header +fwrite(plik, header.ver, 'ubit8'); +fwrite(plik, header.sample_type, 'ubit16'); +fwrite(plik, header.ch_no, 'uint8'); +fwrite(plik, header.Fs, 'uint32'); + +fwrite(plik, x, sample_type); +fclose(plik); \ No newline at end of file diff --git a/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/writewav.m b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/writewav.m new file mode 100644 index 0000000000000000000000000000000000000000..c51c0cf427e7a707c95ba5322b92a34ce46eec2d --- /dev/null +++ b/DSPE_lib_minGW/MinGW-W64_8.1.0/toolbox/writewav.m @@ -0,0 +1,234 @@ +function writewav(y,wavefile,N_start,Fs, reset) +%WAVWRITE Write Microsoft WAVE (".wav") sound file. +% WAVWRITE(Y,FS,NBITS,WAVEFILE) writes data Y to a Windows WAVE +% file specified by the file name WAVEFILE, with a sample rate +% of FS Hz and with NBITS number of bits. NBITS must be 8 or 16. +% Stereo data should be specified as a matrix with two columns. +% Amplitude values outside the range [-1,+1] are clipped. +% +% WAVWRITE(Y,FS,WAVEFILE) assumes NBITS=16 bits. +% WAVWRITE(Y,WAVEFILE) assumes NBITS=16 bits and FS=8000 Hz. +% +% See also WAVREAD, AUWRITE. + +% Copyright 1984-2000 The MathWorks, Inc. +% $Revision: 5.10 $ $Date: 2000/06/01 17:29:55 $ + +% D. Orofino, 11/95 +% Marek Blok 23.05.2002 + +%% Parse inputs: +%error(nargchk(2,5,nargin)); +%if nargin < 3, +% wavefile = Fs; +% Fs = 8000; +% nbits = 16; +%elseif nargin < 4, +% wavefile = nbits; +% nbits = 16; +%end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% we assume that the data are 16bit mono wav file % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +if (reset==1) | (exist(wavefile)==0), + %even if file exists you should start from the begining + delete(wavefile); + + %prepare and write new header + % Determine number of bytes in chunks + % (not including pad bytes, if needed): + % ---------------------------------- + % 'RIFF' 4 bytes + % size 4 bytes (ulong) + % 'WAVE' 4 bytes + % 'fmt ' 4 bytes + % size 4 bytes (ulong) + % <wave-format> 14 bytes + % <format_specific> 2 bytes (PCM) + % 'data' 4 bytes + % size 4 bytes (ulong) + % <wave-data> N bytes + % ---------------------------------- + + %empty data + total_samples = 0; %samples; % * channels; but: channels=1; + total_bytes = total_samples * 2 %* bytes_per_sample; but: bytes_per_sample = 2; %16bit wav file + + riff_cksize = 36+total_bytes; % Don't include 'RIFF' or its size field + fmt_cksize = 16; % Don't include 'fmt ' or its size field + data_cksize = total_bytes; % Don't include 'data' or its size field + + % Determine pad bytes: + %%16 bit file so there's no need of data padding + %data_pad = rem(data_cksize,2); + %riff_cksize = riff_cksize + data_pad; % + fmt_pad, always 0 + + % ---------------------------------- + % Open file for output: + %% Open file, little-endian: + [fid,err] = fopen(wavefile,'wb','l'); + error(err); + + % Prepare basic chunk structure fields: + % ---------------------------------- + % Write RIFF chunk: + fwrite(fid, 'RIFF', 'char'); %pos: 0B, len: 4B + fwrite(fid, riff_cksize, 'ulong'); %pos: 4B, len: 4B + + % Write WAVE subchunk: + fwrite(fid, 'WAVE', 'char'); %pos: 8B, len: 4B + % Indicate a subchunk (no chunk size) + + % Write <fmt-ck>: + fwrite(fid, 'fmt ', 'char'); %pos: 12B, len: 4B + fwrite(fid, fmt_cksize, 'ulong'); %pos: 16B, len: 4B + + % ---------------------------------- + % Write <wave-format>: + fmt.filename = wavefile; + fmt.wFormatTag = 1; % Data encoding format (1=PCM) + fmt.nChannels = 1; % Number of channels + fmt.nSamplesPerSec = Fs; % Samples per second + fmt.nAvgBytesPerSec = 1*2*Fs; % Avg transfer rate + fmt.nBlockAlign = 1*2; % Block alignment + fmt.nBitsPerSample = 16; % standard <PCM-format-specific> info + + % Create <wave-format> data: + fwrite(fid, fmt.wFormatTag, 'ushort'); %pos: 20B, len: 2B + fwrite(fid, fmt.nChannels, 'ushort'); %pos: 22B, len: 2B + fwrite(fid, fmt.nSamplesPerSec, 'ulong' ); %pos: 24B, len: 4B + fwrite(fid, fmt.nAvgBytesPerSec, 'ulong' ); %pos: 28B, len: 4B + fwrite(fid, fmt.nBlockAlign, 'ushort'); %pos: 32B, len: 2B + + % Write format-specific info: + % Write standard <PCM-format-specific> info: + fwrite(fid, fmt.nBitsPerSample, 'ushort'); %pos: 34B, len: 2B + + + % ---------------------------------- + % Write <data-ck>: + fwrite(fid, 'data', 'char'); %pos: 36B, len: 4B + fwrite(fid, data_cksize, 'ulong'); %pos: 40B, len: 4B + % ------------------% + % header end == 44B % + % ------------------% + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Close file: + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + fclose(fid); +end + +%%when resert==0 +%??? read file header +[fid,err] = fopen(wavefile,'rb','l'); +error(err); +fseek(fid, 4, 'bof'); +riff_cksize=fread(fid, 1, 'ulong'); %pos: 4B, len: 4B +fseek(fid, 40, 'bof'); +data_cksize=fread(fid, 1, 'ulong'); %pos: 40B, len: 4B + +total_bytes = data_cksize; +total_samples = total_bytes/2; +fclose(fid); + +%insert data +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% now we can write the file % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%[fid,err] = fopen(wavefile,'ab','l'); +[fid,err] = fopen(wavefile,'r+','l'); +%riff_cksize=fread(fid, 44, 'uchar') %pos: 4B, len: 4B +fseek(fid, 0, 'eof'); + +% If input is a vector, force it to be a column: +data = y(:); +samples=length(data); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Write <wave-data>, and its pad byte if needed: +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +err = ''; + +data = PCM_Quantize(data); + +dtype='short'; % signed 16-bit + +% Write data, one row at a time (one sample from each channel): +% but only one channel +samples = length(data); +%total_samples = samples; + +fwrite(fid, data, dtype); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%update header +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%whe files where just appended +total_samples = total_samples+samples; % * channels; but: channels=1; +total_bytes = total_samples * 2; %* bytes_per_sample; but: bytes_per_sample = 2; %16bit wav file + +riff_cksize = 36+total_bytes; % Don't include 'RIFF' or its size field +data_cksize = total_bytes; % Don't include 'data' or its size field + +fseek(fid, 4, 'bof'); +fwrite(fid, riff_cksize, 'ulong'); %pos: 4B, len: 4B +fseek(fid, 40, 'bof'); +fwrite(fid, data_cksize, 'ulong'); %pos: 40B, len: 4B + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Close file: +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +fclose(fid); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% end of writewav() +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% ------------------------------------------------------------------------ +% Private functions: +% ------------------------------------------------------------------------ + +% ----------------------------------------------------------------------- +function y = PCM_Quantize(x) +% PCM_Quantize: +% Scale and quantize input data, from [-1, +1] range to +% 16-bit data range. + +% Clip data to normalized range [-1,+1]: +ClipMsg = ['Data clipped during write to file']; +ClipWarn = 0; + +% Determine slope (m) and bias (b) for data scaling: +nbits = 16; +m = 2.^(nbits-1); + +y = round(m .* x); + +% Determine quantized data limits, based on the +% presumed input data limits of [-1, +1]: +qlim = m * [-1 +1]; +qlim(2) = qlim(2)-1; + +% Clip data to quantizer limits: +i = find(y < qlim(1)); +if ~isempty(i), + warning(ClipMsg); ClipWarn=1; + y(i) = qlim(1); +end + +i = find(y > qlim(2)); +if ~isempty(i), + if ~ClipWarn, warning(ClipMsg); end + y(i) = qlim(2); +end + +return + + diff --git a/Ex1/.vscode/launch.json b/Ex1/.vscode/launch.json index aa3e76c53c587e712469eaf01ddf536aac072122..9d44e674a03ebca7eef9edb13802ad68fe2ce314 100644 --- a/Ex1/.vscode/launch.json +++ b/Ex1/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "(gdb) Ex1 — debug run ", + "name": "(gdb) Ex1 — Windows debug run ", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/Ex1_task3_dbg.exe", diff --git a/Ex1/Ex1_task3.cbp b/Ex1/Ex1_task3.cbp index 37f8ce3b6d976a3e694238060e1b0018ba464cfd..a7db99dd15c0b03f27ed8d765a2df1fbd52b67a2 100644 --- a/Ex1/Ex1_task3.cbp +++ b/Ex1/Ex1_task3.cbp @@ -14,18 +14,18 @@ </Build> <Compiler> <Add option="-std=c++0x" /> - <Add option="-m32" /> + <Add option="-m64" /> <Add option="-g" /> <Add option="-DWIN32" /> - <Add directory="../DSPElib/CodeBlocks-m32_TDM_5.1.0/include" /> - <Add directory="../DSPElib/CodeBlocks-m32_TDM_5.1.0/dbg" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/include" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/include/dbg" /> </Compiler> <Linker> <Add option="-static-libgcc" /> - <Add option="-m32" /> + <Add option="-m64" /> <Add library="DSPE" /> <Add library="winmm" /> - <Add directory="../DSPElib/CodeBlocks-m32_TDM_5.1.0/dbg" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/dbg" /> </Linker> <Unit filename="Ex1_task3.cpp" /> <Extensions> diff --git a/Ex2/.vscode/launch.json b/Ex2/.vscode/launch.json index 60af171acc8b456d26078fecd973b5e32059ce70..f66ea162397fe2fa1bf8ebfd1029b44114817b89 100644 --- a/Ex2/.vscode/launch.json +++ b/Ex2/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "(gdb) Ex2 — debug run ", + "name": "(gdb) Ex2 — Windows debug run ", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/Ex2_task1_dbg.exe", diff --git a/Ex2/Ex2_task1.cbp b/Ex2/Ex2_task1.cbp index 13e9ca7f96e311c18ddf209f0b506eed1fb8324a..f5cd3d8e07278e61ef54c860fd0abab6be101da3 100644 --- a/Ex2/Ex2_task1.cbp +++ b/Ex2/Ex2_task1.cbp @@ -14,18 +14,18 @@ </Build> <Compiler> <Add option="-std=c++0x" /> - <Add option="-m32" /> + <Add option="-m64" /> <Add option="-g" /> <Add option="-DWIN32" /> - <Add directory="../DSPElib/CodeBlocks-m32_TDM_5.1.0/include" /> - <Add directory="../DSPElib/CodeBlocks-m32_TDM_5.1.0/dbg" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/include" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/include/dbg" /> </Compiler> <Linker> <Add option="-static-libgcc" /> - <Add option="-m32" /> + <Add option="-m64" /> <Add library="DSPE" /> <Add library="winmm" /> - <Add directory="../DSPElib/CodeBlocks-m32_TDM_5.1.0/dbg" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/dbg" /> </Linker> <Unit filename="Ex2_task1.cpp" /> <Extensions> diff --git a/Ex3/.vscode/c_cpp_properties.json b/Ex3/.vscode/c_cpp_properties.json new file mode 100644 index 0000000000000000000000000000000000000000..11c576f694c99f7b30d0d5015bc0fede255966c2 --- /dev/null +++ b/Ex3/.vscode/c_cpp_properties.json @@ -0,0 +1,65 @@ +{ + "configurations": [ + { + "name": "Windows-Release", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/../DSPE_lib_minGW/MinGW-W64_8.1.0/include/**" + ], + "defines": [ + "WIN32", + "__DEBUG__=0" + ], + //"compilerPath": "gcc.exe", + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "gcc-x64" + }, + { + "name": "Linux-Release", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/../DSPE_lib_minGW/MinGW-W64_8.1.0/include/**" + ], + "defines": [ + "WIN32", + "__DEBUG__=0" + ], + "compilerPath": "gcc.exe", + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "gcc-x64" + }, + { + "name": "Windows-Debug", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/../DSPE_lib_minGW/MinGW-W64_8.1.0/include/**" + ], + "defines": [ + "WIN32", + "__DEBUG__=1" + ], + //"compilerPath": "gcc.exe", + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "gcc-x64" + }, + { + "name": "Linux-Debug", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/../DSPE_lib_minGW/MinGW-W64_8.1.0/include/**" + ], + "defines": [ + "WIN32", + "__DEBUG__=1" + ], + "compilerPath": "gcc.exe", + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "gcc-x64" + } +], + "version": 4 +} \ No newline at end of file diff --git a/Ex3/.vscode/launch.json b/Ex3/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..3ebdbd93e6a13d674460f2ecf90a6eb881f9dfdf --- /dev/null +++ b/Ex3/.vscode/launch.json @@ -0,0 +1,29 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Ex3 — widnows debug run ", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/Ex3_task3_dbg.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", +// "miDebuggerPath": "d:/CodeBlocks_20_03/MinGW/bin/gdb.exe", + "setupCommands": [ + { + "description": "Włącz formatowanie kodu dla gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "Build Ex3_task3.cpp" + } + ] +} \ No newline at end of file diff --git a/Ex3/.vscode/tasks.json b/Ex3/.vscode/tasks.json new file mode 100644 index 0000000000000000000000000000000000000000..81f55146f8246c0f1fe4f06dd4d4b4be66ce15ff --- /dev/null +++ b/Ex3/.vscode/tasks.json @@ -0,0 +1,33 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + // https://code.visualstudio.com/docs/editor/tasks + // ${command:cpptools.activeConfigName} + "tasks": [ + { + "label": "Build Ex3_task3.cpp", + "type": "shell", + "command": "make build -f Makefile.main FILE=Ex3_task3 VS_CFG=${command:cpptools.activeConfigName}", + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "echo": true + }, + "problemMatcher": "$gcc" + }, + { + "label": "Clean Ex3_task3.cpp", + "type": "shell", + "command": "make clean -f Makefile.main VS_CFG=${command:cpptools.activeConfigName}", + "group": "build", + "presentation": { + "echo": true + }, + "problemMatcher": "$gcc" + } + + ] +} \ No newline at end of file diff --git a/Ex3/Ex3_task3.cbp b/Ex3/Ex3_task3.cbp new file mode 100644 index 0000000000000000000000000000000000000000..3ec14bc0c8ba64614ba8f725e7054efd7fb8f8a0 --- /dev/null +++ b/Ex3/Ex3_task3.cbp @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<CodeBlocks_project_file> + <FileVersion major="1" minor="6" /> + <Project> + <Option title="Ex3_task3" /> + <Option pch_mode="2" /> + <Option compiler="gcc" /> + <Build> + <Target title="default"> + <Option output="Ex3_task3" prefix_auto="1" extension_auto="1" /> + <Option type="1" /> + <Option compiler="gcc" /> + </Target> + </Build> + <Compiler> + <Add option="-m64" /> + <Add option="-g" /> + <Add option="-std=c++0x" /> + <Add option="-DWIN32" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/include" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/include/dbg" /> + </Compiler> + <Linker> + <Add option="-static-libgcc" /> + <Add option="-m64" /> + <Add library="DSPE" /> + <Add library="winmm" /> + <Add directory="../DSPE_lib_minGW/MinGW-W64_8.1.0/dbg" /> + </Linker> + <Unit filename="Ex3_task3.cpp" /> + <Extensions> + <lib_finder disable_auto="1" /> + </Extensions> + </Project> +</CodeBlocks_project_file> diff --git a/Ex3/Ex3_task3.cpp b/Ex3/Ex3_task3.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d29e70d384c9f6168b4b94a9d4912ec1a13cd6a2 --- /dev/null +++ b/Ex3/Ex3_task3.cpp @@ -0,0 +1,151 @@ +/*! Laboratory: Advanced signal processing of digital telecommunications + * (Zaawansowane przetwarzanie sygnałów telekomunikacji cyfrowej) + * Ex. 3. task 4. + * - reading filter impulse response from file + * (script generating data file: ./matlab/design_task_3.m) + * - two-stage interpolator L = 20 + * + * \author Marek Blok + * \date 2021.06.25 + */ +#include <sstream> + +#include <DSP_lib.h> + +int main(int argn, char *args[]) +{ + /*************************************************************/ + // Log file setup + DSP::log.SetLogFileName("log_file.txt"); + DSP::log.SetLogState(DSP::e::LogState::file | DSP::e::LogState::console); + + DSP::log << DSP::lib_version_string() << endl << endl; + /*************************************************************/ + + long int Fp1, Fp2, F_symb; + DSP::LoadCoef coef_info; + int N_rc, N2; + unsigned int L1, L2; + DSP::Float_vector h_rc, h2; + + coef_info.Open("ex3_task3_h_rc.coef", "matlab"); + N_rc = coef_info.GetSize(0); + if (N_rc < 1) + { + DSP::log << DSP::e::LogMode::Error << "No ex3_task3_h_rc.coef: aborting" << endl; + return -1; + } + else + { + coef_info.Load(h_rc); + Fp1 = coef_info.Fp; + } + /*************************************************************/ + coef_info.Open("ex3_task3_h2.coef", "matlab"); + N2 = coef_info.GetSize(0); + if (N2 < 1) + { + DSP::log << DSP::e::LogMode::Error << "No ex3_task3_h2.coef: aborting" << endl; + return -1; + } + else + { + coef_info.Load(h2); + Fp2 = coef_info.Fp; + } + /*************************************************************/ + + DSP::Clock_ptr SymbolClock, SecondClock; + SymbolClock=DSP::Clock::CreateMasterClock(); + + + //DSP::u::WaveInput AudioIn(MasterClock, "test.wav", "."); + //F_symb = AudioIn.GetSamplingRate(); + + DSP::u::FileInput BinData(SymbolClock, "ex3_task3.cpp", 2U, DSP::e::SampleType::ST_bit, DSP::e::FileType::FT_raw); + F_symb = 2400; + DSP::u::PSKencoder PSKencoder(DSP::e::PSK_type::QPSK_A); + + L1 = Fp1 / F_symb; + L2 = Fp2 / Fp1; + DSP::log << "Fsymb = " << F_symb << ", Fp1 = " << Fp1 << ", Fp2 = " << Fp2 << ", L1 = " << L1 << ", L2 = " << L2 << endl; + + SecondClock=DSP::Clock::GetClock(SymbolClock, L1, 1); + + DSP::u::SamplingRateConversion SRC1(true, SymbolClock, L1, 1, h_rc); + SRC1.SetName("SRC1"); + + DSP::u::SamplingRateConversion SRC2(true, SecondClock, L2, 1, h2); + SRC2.SetName("SRC2"); + DSP::u::DDScos Heter(SRC2.GetOutputClock(), true, 0.5, (DSP::M_PIx2*2500)/DSP::Float(Fp2)); + DSP::u::Multiplication Mul(0, 2); + DSP::u::Vacuum V1; + + + // Output to the soundcard + DSP::u::AudioOutput SoundOut(Fp2, 1, 16); + DSP::u::FileOutput FileOut1("ex3_task3a.flt", DSP::e::SampleType::ST_float, 2, DSP::e::FileType::FT_flt, Fp1); + // Output to the mono 16bit *.wav file + DSP::u::FileOutput FileOut2a("ex3_task3b.wav", DSP::e::SampleType::ST_short, 1, DSP::e::FileType::FT_wav, Fp2); + DSP::u::FileOutput FileOut2b("ex3_task3b.flt", DSP::e::SampleType::ST_float, 1, DSP::e::FileType::FT_flt, Fp2); + + /*************************************************************/ + // Connections definitions + //AudioIn.Output("out") >> SRC1.Input("in"); + BinData.Output("out") >> PSKencoder.Input("in"); + PSKencoder.Output("out") >> SRC1.Input("in"); + + SRC1.Output("out") >> FileOut1.Input("in"); + SRC1.Output("out") >> SRC2.Input("in"); + + SRC2.Output("out") >> Mul.Input("in1"); + Heter.Output("out") >> Mul.Input("in2"); + + Mul.Output("out.im") >> V1.Input("in"); + + Mul.Output("out.re") >> SoundOut.Input("in"); + Mul.Output("out.re") >> FileOut2a.Input("in"); + Mul.Output("out.re") >> FileOut2b.Input("in"); + + + ///////////////////////////////// + // check if there are signals + // connected to all inputs + DSP::Component::CheckInputsOfAllComponents(); + + // *********************************** // + DSP::Clock::SchemeToDOTfile(SymbolClock, "Ex3_task3.dot"); + + // *********************************** // + int SamplesInSegment = 4*512; + __int64 NoOfSamplesProcessed = 0; + // 10 seconds + #define MAX_SAMPLES_TO_PROCESS 10*Fp1 + while(NoOfSamplesProcessed < MAX_SAMPLES_TO_PROCESS) + { + + // ********************************************************** // + DSP::Clock::Execute(SymbolClock, SamplesInSegment); + // ********************************************************** // + + int bytes_read = BinData.GetBytesRead(); + DSP::log << "BinData.GetBytesRead() = " << bytes_read << endl; + if (bytes_read > 0) + { + NoOfSamplesProcessed = 0; // Play the whole file + } + else // Play 200ms more + { + if (NoOfSamplesProcessed < MAX_SAMPLES_TO_PROCESS - Fp1/5) + NoOfSamplesProcessed = MAX_SAMPLES_TO_PROCESS - Fp1/5; + } + + NoOfSamplesProcessed += SamplesInSegment; + // ********************************************************** // + } + + /*************************************************************/ + DSP::Clock::FreeClocks(); + + return 0; +} diff --git a/Ex3/Makefile b/Ex3/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c94c79f51791f3dffcb970c87be83384cef43774 --- /dev/null +++ b/Ex3/Makefile @@ -0,0 +1,85 @@ +# Run: make Release +# Run: make Debug +CC=g++ +# comflag = -m32 +# comflag = -m64 +comflag = $(COMFLAG) + +DSPElib_DIR = ../../_DSPE_lib_minGW_/$(DSPElib_SUBDIR) + +SRC_DIR = . +SRC_CPP_SUBDIR = . + +#DFLAGS = -DWIN32 -DDEVCPP + +# -D INCLUDE_DSPE_EXAMPLES # TODO: użycie w ramach kompilacji Main.cpp w trybie DEBUG +ifeq ($(MODE),Release) + CFLAGS = $(comflag) -std=c++0x -O3 -Wall -c -fmessage-length=0 -fno-strict-aliasing + LINKER_FLAGS = $(comflag) -s -static-libgcc -static-libstdc++ $(MISC_LINKER_FLAGS) + INCLUDES := -I"$(DSPElib_DIR)/include" -I"$(DSPElib_DIR)/include/rls" + DSPElib_FULLDIR = $(DSPElib_DIR)/rls + EXE_FILENAME = $(CPP_FILENAME)_rls.exe +else + CFLAGS = $(comflag) -std=c++0x -O0 -g3 -Wall -c -fmessage-length=0 -W -Wshadow -Wconversion -fstrict-aliasing -fmax-errors=5 + LINKER_FLAGS = $(comflag) -static-libgcc -static-libstdc++ $(MISC_LINKER_FLAGS) + INCLUDES := -I"$(DSPElib_DIR)/include" -I"$(DSPElib_DIR)/include/dbg" + DSPElib_FULLDIR = $(DSPElib_DIR)/dbg + EXE_FILENAME = $(CPP_FILENAME)_dbg.exe +endif +# -U__STRICT_ANSI__ jest potrzebne do kompilacji debug_new.cpp, jezeli pominac ten plik to mozna rowniez wyrzucic te opcje +#CFLAGS_debug = $(comflag) -std=c++0x -O0 -g3 -Wall -c -fmessage-length=0 -W -Wshadow -Wco#nversion -fstrict-aliasing -U__STRICT_ANSI__ + +SOURCES_NAMES = +SOURCES_NAMES += $(CPP_FILENAME).cpp +SOURCES = $(addprefix $(SRC_CPP_SUBDIR)/,$(SOURCES_NAMES)) + +SOURCES_DBG = +# SOURCES_DBG += $(SRC_DIR)/Main.cpp + +# ################################################# # +# DEBUG +OBJECTS := $(SOURCES:%.cpp=$(OUT_DIR)/%.o) +DEPENDS := $(SOURCES:%.cpp=$(OUT_DIR)/%.d) + +# ################################################# # +-include $(DEPENDS) + +all: build + + +# ########################################################################################### # +# ########################################################################################### # +build: $(SRC_DIR)/$(EXE_FILENAME) + +$(SRC_DIR)/$(EXE_FILENAME): $(OBJECTS) + @echo $(EXE_FILENAME) + $(CC) -L$(DSPElib_FULLDIR) $(OBJECTS) -o"$(SRC_DIR)/$(EXE_FILENAME)" $(LINKER_FLAGS) -lDSPE $(LIBS) + +# ########################################################################################### # +# ########################################################################################### # +# Z podanej listy usuwany $(OUT_DIR_WIN_RLS)/ oraz '.o' zamieniamy na '.cpp' +$(OBJECTS): $(OUT_DIR)/%.o : %.cpp + @echo $(@D) $< $@ + + #mkdir -p $(OUT_DIR)/$(SRC_CPP_SUBDIR) + mkdir -p $(@D) + $(CC) $(DFLAGS) $(CFLAGS) $(INCLUDES) -MMD $< -o $@ + + +clean: + @echo MODE: $(MODE) + + @if [ -d "$(OUT_DIR)" ]; then \ + echo "cleaning $(OUT_DIR_DBG) ..."; \ + #find $(OUT_DIR)/ -name "*.o" -type f -delete; \ + rm -rf $(OUT_DIR)/*.d; \ + rm -rf $(OUT_DIR)/*.o; \ + rm -rf $(OUT_DIR); \ + echo "cleaned $(OUT_DIR)"; \ + fi + rm -rf "$(SRC_DIR)/$(EXE_FILENAME)"; \ + #rm -rf "$(SRC_DIR)/*.gif"; \ + #rm -rf "$(SRC_DIR)/*.dot"; \ + +.PHONY: all build clean + diff --git a/Ex3/Makefile.main b/Ex3/Makefile.main new file mode 100644 index 0000000000000000000000000000000000000000..cf6c368f484646f2b2a80c30863e62c3d1e7ec7f --- /dev/null +++ b/Ex3/Makefile.main @@ -0,0 +1,60 @@ +# (View > Command Palette) => "Convert Indentation to Tabs" + +ifeq ($(VS_CFG),Windows-Debug) + MAKEFILE = "Makefile" + MODE = Debug + COMFLAG = -m64 + + OUT_DIR = ./out_win_dbg + DSPElib_SUBDIR = MinGW-W64_8.1.0 + MISC_LINKER_FLAGS = -static + LIBS = -lwinmm -lws2_32 + DFLAGS = -DWIN32 -DDEVCPP +endif +ifeq ($(VS_CFG),Windows-Release) + MAKEFILE = "Makefile" + MODE = Release + COMFLAG = -m64 + + OUT_DIR = ./out_win_rls + DSPElib_SUBDIR = MinGW-W64_8.1.0 + MISC_LINKER_FLAGS = -static + LIBS = -lwinmm -lws2_32 + DFLAGS = -DWIN32 -DDEVCPP +endif +ifeq ($(VS_CFG),Linux-Debug) + MAKEFILE = "Makefile" + MODE = Debug + COMFLAG = + + OUT_DIR = ./out_linux_dbg + DSPElib_SUBDIR = $(shell gcc -dumpmachine)-gcc_$(shell gcc -dumpversion) + MISC_LINKER_FLAGS = + LIBS := -lasound + DFLAGS = +endif +ifeq ($(VS_CFG),Linux-Release) + MAKEFILE = "Makefile" + MODE = Release + COMFLAG = + + OUT_DIR = ./out_linux_rls + DSPElib_SUBDIR = $(shell gcc -dumpmachine)-gcc_$(shell gcc -dumpversion) + MISC_LINKER_FLAGS = + LIBS := -lasound + DFLAGS = +endif + + + +build: + @echo "Building $(VS_CFG)" + @echo $(VS_CFG): $(MODE) // $(MAKEFILE) + make build CPP_FILENAME=$(FILE) MODE=$(MODE) COMFLAG=$(COMFLAG) DFLAGS="$(DFLAGS)" LIBS="$(LIBS)" OUT_DIR=$(OUT_DIR) DSPElib_SUBDIR=$(DSPElib_SUBDIR) MISC_LINKER_FLAGS="$(MISC_LINKER_FLAGS)" -f $(MAKEFILE) + +clean: + @echo "Cleaning $(VS_CFG)" + @echo $(VS_CFG): $(MODE) // $(MAKEFILE) + make clean MODE=$(MODE) OUT_DIR=$(OUT_DIR) -f $(MAKEFILE) + + diff --git a/Ex3/matlab/MultiSRC_gui_v2.m b/Ex3/matlab/MultiSRC_gui_v2.m new file mode 100644 index 0000000000000000000000000000000000000000..10b813f153bf237a3f83375ceefb228199d3ae9e --- /dev/null +++ b/Ex3/matlab/MultiSRC_gui_v2.m @@ -0,0 +1,858 @@ +% Wielostopniowa zmiana szybkoœci próbkowania +function MultiSRC_gui_v2 + +clear all +fig = findobj('tag', 'MultiSRC_gui_v2') +if ~isempty(fig) + close(fig); +end +clc +set(0, 'DefaultUicontrolFontName', 'Times New Roman CE') + +global fold +global fnew + +global L +global M + +global ile_stopni + +global nr_sygnalu + + +function result = is_calkowita(liczba) + +if liczba == fix(liczba) + result = true; + else + result = false; + end +end + +function keyPress(hObject, eventdata) + switch eventdata.Key + case 'f11' + guihelp; + end +end + + +function Help(hObject, eventdata) + guihelp; +end + + function Odswiez(hObject, eventdata) + + fold = str2double(get(edtFold, 'String')); + fnew = str2double(get(edtFnew, 'String')); + + if isnan(fold) || isnan(fnew) || ~is_calkowita(fold) || ~is_calkowita(fnew) + msgbox('Nieprawid³owa wartoœæ Fold lub Fnew.', 'B³¹d'); + return; + end + + L = fnew / gcd(fold, fnew); + M = fold / gcd(fold, fnew); + + Fmax = min(0.5/L,0.5/M)*(fold*L); + set(txtFmax, 'String', sprintf('F_max = %.1f [Hz]', Fmax)); + + set(txtL, 'String', sprintf('L = %d', L)); + set(txtM, 'String', sprintf('M = %d', M)); + + set(edtL1, 'String', ''); + set(edtL2, 'String', ''); + set(edtL3, 'String', ''); + set(edtL4, 'String', ''); + set(edtM1, 'String', ''); + set(edtM2, 'String', ''); + set(edtM3, 'String', ''); + set(edtM4, 'String', ''); + set(edtFP1, 'String', ''); + set(edtFP2, 'String', ''); + set(edtFP3, 'String', ''); + set(edtFP4, 'String', ''); + set(edtFS1, 'String', ''); + set(edtFS2, 'String', ''); + set(edtFS3, 'String', ''); + set(edtFS4, 'String', ''); + for i = 2:7 + if ishandle(i) + close(i); + end + end + end + + +function WyborSygnalu(hObject, eventdata) + nr_sygnalu = get(hObject, 'value'); +end + +function WyliczDomyslneFsFp(hObject, eventdata) + +Fp_factor = str2double(get(edtFp_factor, 'String')); + +L1 = str2double(get(edtL1, 'String')); +M1 = str2double(get(edtM1, 'String')); +L2 = str2double(get(edtL2, 'String')); +M2 = str2double(get(edtM2, 'String')); +L3 = str2double(get(edtL3, 'String')); +M3 = str2double(get(edtM3, 'String')); +L4 = str2double(get(edtL4, 'String')); +M4 = str2double(get(edtM4, 'String')); + +if (ile_stopni == 1) + Li = L1; + Mi = M1; + + if isnan(L1) || isnan(M1) || ~is_calkowita(L1) || ~is_calkowita(M1) + msgbox('Nieprawid³owa wartoœæ w Li lub Mi.', 'B³¹d'); + return; + end + + if prod(Li) ~= L || prod(Mi) ~= M + msgbox('Iloczyn Li (Mi) musi byæ równy L (M).', 'B³¹d'); + return; + end + + % Wartoœci referencyjne implementacji jednostopniowej +% Fp = min(0.4/L,0.4/M)*(fold*L1); + Fs = min(0.5/L,0.5/M)*(fold*L); % filtr dla implementacji jednostopniowej pracuje na czêstotliwoœci Fold*L + Fp = (1-Fp_factor)*Fs; + Fmax = Fs; % maksymalna czêstotliwoœæ sk³adowych sygna³u na wyjœciu implementacji jednostopniowej + + % Wartoœci dla pierwszego stopnia +% Fp1 = min(0.4/L1,0.4/M1)*(fold*L1); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1 + Fs1 = min(0.5/L1,0.5/M1)*(fold*L1); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1 + Fp1 = (1-Fp_factor)*Fs1; + % alias jest dopuszczalny do szybkoœci Fmax + if (Fs1 > Fmax), + Fs1 = Fs1 + (Fs1-Fmax); + end + if (Fp1 >= Fp), + Fp1 = Fp; % wybieramy szersze pasmo przejœciowe + else + disp('Fp1 < Fp'); + end + if (Fs1 < Fmax) + disp('Fs1 < Fmax'); + end + fp1 = Fp1/(fold*L1); fs1 = Fs1/(fold*L1); + Fmax1 = min(Fmax, Fs1); + if (Fmax1 < Fmax) + set(txtFmax2, 'String', sprintf('F_max = %.1f [Hz]', Fmax1), 'ForegroundColor', 'red', 'FontWeight', 'Bold'); + else + set(txtFmax2, 'String', sprintf('F_max = %.1f [Hz]', Fmax1), 'ForegroundColor', 'black', 'FontWeight', 'normal'); + end + + set(edtFP1, 'String', fp1); + set(edtFS1, 'String', fs1); +end + +if (ile_stopni == 2) + Li = [ L1, L2 ]; + Mi = [ M1, M2 ]; + + if isnan(L1) || isnan(M1) || ~is_calkowita(L1) || ~is_calkowita(M1) ||... + isnan(L2) || isnan(M2) || ~is_calkowita(L2) || ~is_calkowita(M2) + msgbox('Nieprawid³owa wartoœæ w Li lub Mi.', 'B³¹d'); + return; + end + + if prod(Li) ~= L || prod(Mi) ~= M + msgbox('Iloczyn Li (Mi) musi byæ równy L (M).', 'B³¹d'); + return; + end + + % Wartoœci referencyjne implementacji jednostopniowej +% Fp = min(0.4/L,0.4/M)*(fold*L1); + Fs = min(0.5/L,0.5/M)*(fold*L); % filtr dla implementacji jednostopniowej pracuje na czêstotliwoœci Fold*L +% Fp = 0.8*Fs; + Fp = (1-Fp_factor)*Fs; + Fmax = Fs; % maksymalna czêstotliwoœæ sk³adowych sygna³u na wyjœciu implementacji jednostopniowej + + % Wartoœci dla pierwszego stopnia +% Fp1 = min(0.4/L1,0.4/M1)*(fold*L1); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1 + Fs1 = min(0.5/L1,0.5/M1)*(fold*L1); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1 + Fp1 = (1-Fp_factor)*Fs1; + % alias jest dopuszczalny do szybkoœci Fmax + if (Fs1 >= Fmax), + Fs1 = Fs1 + (Fs1-Fmax); + end + if (Fp1 >= Fp), + Fp1 = Fp; % wybieramy szersze pasmo przejœciowe + else + disp('Fp1 < Fp'); + end + if (Fs1 < Fmax) + disp('Fs1 < Fmax'); + end + fp1 = Fp1/(fold*L1); fs1 = Fs1/(fold*L1); + Fmax1 = min(Fmax, Fs1); + if (Fmax1 < Fmax) + disp('Fmax1 < Fmax'); + end + + + % Wartoœci dla drugiego stopnia +% Fp2 = min(0.4/L2,0.4/M2)*(fold*L1/M1*L2); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci fold*L1/M1*L2 + Fs2 = min(0.5/L2,0.5/M2)*(fold*L1/M1*L2); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1/M1*L2 + Fp2 = (1-Fp_factor)*Fs2; + % alias jest dopuszczalny do czêstotliwoœci Fmax + if (Fs2 >= Fmax), + Fs2 = Fs2 + (Fs2-Fmax); + end + if (Fp2 >= Fp), + Fp2 = Fp; % wybieramy szersze pasmo przejœciowe + else + disp('Fp2 < Fp'); + end + if (Fs2 < Fmax) + disp('Fs2 < Fmax'); + end + fp2 = Fp2/(fold*L1/M1*L2); fs2 = Fs2/(fold*L1/M1*L2); + Fmax2 = min(Fmax1, Fs2); + if (Fmax2 < Fmax) + set(txtFmax2, 'String', sprintf('F_max = %.1f [Hz]', Fmax2), 'ForegroundColor', 'red', 'FontWeight', 'Bold'); + else + set(txtFmax2, 'String', sprintf('F_max = %.1f [Hz]', Fmax2), 'ForegroundColor', 'black', 'FontWeight', 'normal'); + end + +% fp1 = (min(0.4/L,0.4/M)*fnew)/(fold*L1); +% fs1 = min(0.5/L1,0.5/M1); +% fp2 = (min(0.4/L,0.4/M)*fnew)/(fold*L1*L2/M1); +% fs2 = min(0.5/L2,0.5/M2); + set(edtFP1, 'String', fp1); + set(edtFS1, 'String', fs1); + set(edtFP2, 'String', fp2); + set(edtFS2, 'String', fs2); +end + +if (ile_stopni == 3) + Li = [ L1, L2, L3 ]; + Mi = [ M1, M2, M3 ]; + + if isnan(L1) || isnan(M1) || ~is_calkowita(L1) || ~is_calkowita(M1) ||... + isnan(L2) || isnan(M2) || ~is_calkowita(L2) || ~is_calkowita(M2) ||... + isnan(L3) || isnan(M3) || ~is_calkowita(L3) || ~is_calkowita(M3) + msgbox('Nieprawid³owa wartoœæ w Li lub Mi.', 'B³¹d'); + return; + end + + if prod(Li) ~= L || prod(Mi) ~= M + msgbox('Iloczyn Li (Mi) musi byæ równy L (M).', 'B³¹d'); + return; + end + + % Wartoœci referencyjne implementacji jednostopniowej +% Fp = min(0.4/L,0.4/M)*(fold*L1); + Fs = min(0.5/L,0.5/M)*(fold*L); % filtr dla implementacji jednostopniowej pracuje na czêstotliwoœci Fold*L + Fp = (1-Fp_factor)*Fs; + Fmax = Fs; % maksymalna czêstotliwoœæ sk³adowych sygna³u na wyjœciu implementacji jednostopniowej + +% fp1 = (min(0.4/L,0.4/M)*fnew)/(fold*L1); +% fs1 = min(0.5/L1,0.5/M1); +% Fp1 = min(0.4/L1,0.4/M1)*(fold*L1); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1 + Fs1 = min(0.5/L1,0.5/M1)*(fold*L1); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1 + Fp1 = (1-Fp_factor)*Fs1; + % alias jest dopuszczalny do szybkoœci Fmax + if (Fs1 >= Fmax), + Fs1 = Fs1 + (Fs1-Fmax); + end + if (Fp1 >= Fp), + Fp1 = Fp; % wybieramy szersze pasmo przejœciowe + else + disp('Fp1 < Fp'); + end + if (Fs1 < Fmax) + disp('Fs1 < Fmax'); + end + fp1 = Fp1/(fold*L1); fs1 = Fs1/(fold*L1); + Fmax1 = min(Fmax, Fs1); + if (Fmax1 < Fmax) + disp('Fmax1 < Fmax'); + end + +% fp2 = (min(0.4/L,0.4/M)*fnew)/(fold*L1*L2/M1); +% fs2 = min(0.5/L2,0.5/M2); + % Wartoœci dla drugiego stopnia +% Fp2 = min(0.4/L2,0.4/M2)*(fold*L1/M1*L2); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci fold*L1/M1*L2 + Fs2 = min(0.5/L2,0.5/M2)*(fold*L1/M1*L2); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1/M1*L2 + Fp2 = (1-Fp_factor)*Fs2; + % alias jest dopuszczalny do szybkoœci Fmax + if (Fs2 >= Fmax), + Fs2 = Fs2 + (Fs2-Fmax); + end + if (Fp2 >= Fp), + Fp2 = Fp; % wybieramy szersze pasmo przejœciowe + else + disp('Fp2 < Fp'); + end + if (Fs2 < Fmax) + disp('Fs2 < Fmax'); + end + fp2 = Fp2/(fold*L1/M1*L2); fs2 = Fs2/(fold*L1/M1*L2); + Fmax2 = min(Fmax1, Fs2); + if (Fmax2 < Fmax) + disp('Fmax2 < Fmax'); + end + +% fp3 = (min(0.4/L,0.4/M)*fnew)/(fold*L1*L2*L3/(M1*M2)); +% fs3 = min(0.5/L3,0.5/M3); + % Wartoœci dla TRZECIEGO stopnia +% Fp3 = min(0.4/L3,0.4/M3)*(fold*L1/M1*L2/M2*L3); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci fold*L1/M1*L2 + Fs3 = min(0.5/L3,0.5/M3)*(fold*L1/M1*L2/M2*L3); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1/M1*L2 + Fp3 = (1-Fp_factor)*Fs3; + % alias jest dopuszczalny do szybkoœci Fmax + if (Fs3 >= Fmax), + Fs3 = Fs3 + (Fs3-Fmax); + end + if (Fp3 >= Fp), + Fp3 = Fp; % wybieramy szersze pasmo przejœciowe + else + disp('Fp3 < Fp'); + end + if (Fs3 < Fmax) + disp('Fs3 < Fmax'); + end + fp3 = Fp3/(fold*L1/M1*L2/M2*L3); fs3 = Fs3/(fold*L1/M1*L2/M2*L3); + Fmax3 = min(Fmax2, Fs3); + if (Fmax3 < Fmax) + set(txtFmax2, 'String', sprintf('F_max = %.1f [Hz]', Fmax3), 'ForegroundColor', 'red', 'FontWeight', 'Bold'); + else + set(txtFmax2, 'String', sprintf('F_max = %.1f [Hz]', Fmax3), 'ForegroundColor', 'black', 'FontWeight', 'normal'); + end + + + set(edtFP1, 'String', fp1); + set(edtFS1, 'String', fs1); + set(edtFP2, 'String', fp2); + set(edtFS2, 'String', fs2); + set(edtFP3, 'String', fp3); + set(edtFS3, 'String', fs3); +end + +if (ile_stopni == 4) + Li = [ L1, L2, L3, L4 ]; + Mi = [ M1, M2, M3, M4 ]; + + if isnan(L1) || isnan(M1) || ~is_calkowita(L1) || ~is_calkowita(M1) ||... + isnan(L2) || isnan(M2) || ~is_calkowita(L2) || ~is_calkowita(M2) ||... + isnan(L3) || isnan(M3) || ~is_calkowita(L3) || ~is_calkowita(M3) ||... + isnan(L4) || isnan(M4) || ~is_calkowita(L4) || ~is_calkowita(M4) + msgbox('Nieprawid³owa wartoœæ w Li lub Mi.', 'B³¹d'); + return; + end + + if prod(Li) ~= L || prod(Mi) ~= M + msgbox('Iloczyn Li (Mi) musi byæ równy L (M).', 'B³¹d'); + return; + end + + % Wartoœci referencyjne implementacji jednostopniowej +% Fp = min(0.4/L,0.4/M)*(fold*L1); + Fs = min(0.5/L,0.5/M)*(fold*L); % filtr dla implementacji jednostopniowej pracuje na czêstotliwoœci Fold*L + Fp = (1-Fp_factor)*Fs; + Fmax = Fs; % maksymalna czêstotliwoœæ sk³adowych sygna³u na wyjœciu implementacji jednostopniowej + +% fp1 = (min(0.4/L,0.4/M)*fnew)/(fold*L1); +% fs1 = min(0.5/L1,0.5/M1); +% Fp1 = min(0.4/L1,0.4/M1)*(fold*L1); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1 + Fs1 = min(0.5/L1,0.5/M1)*(fold*L1); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1 + Fp1 = (1-Fp_factor)*Fs1; + % alias jest dopuszczalny do szybkoœci Fmax + if (Fs1 >= Fmax), + Fs1 = Fs1 + (Fs1-Fmax); + end + if (Fp1 >= Fp), + Fp1 = Fp; % wybieramy szersze pasmo przejœciowe + else + disp('Fp1 < Fp'); + end + if (Fs1 < Fmax) + disp('Fs1 < Fmax'); + end + fp1 = Fp1/(fold*L1); fs1 = Fs1/(fold*L1); + Fmax1 = min(Fmax, Fs1); + if (Fmax1 < Fmax) + disp('Fmax1 < Fmax'); + end + +% fp2 = (min(0.4/L,0.4/M)*fnew)/(fold*L1*L2/M1); +% fs2 = min(0.5/L2,0.5/M2); + % Wartoœci dla drugiego stopnia +% Fp2 = min(0.4/L2,0.4/M2)*(fold*L1/M1*L2); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci fold*L1/M1*L2 + Fs2 = min(0.5/L2,0.5/M2)*(fold*L1/M1*L2); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1/M1*L2 + Fp2 = (1-Fp_factor)*Fs2; + % alias jest dopuszczalny do szybkoœci Fmax + if (Fs2 >= Fmax), + Fs2 = Fs2 + (Fs2-Fmax); + end + if (Fp2 >= Fp), + Fp2 = Fp; % wybieramy szersze pasmo przejœciowe + else + disp('Fp2 < Fp'); + end + if (Fs2 < Fmax) + disp('Fs2 < Fmax'); + end + fp2 = Fp2/(fold*L1/M1*L2); fs2 = Fs2/(fold*L1/M1*L2); + Fmax2 = min(Fmax1, Fs2); + if (Fmax2 < Fmax) + disp('Fmax2 < Fmax'); + end + +% fp3 = (min(0.4/L,0.4/M)*fnew)/(fold*L1*L2*L3/(M1*M2)); +% fs3 = min(0.5/L3,0.5/M3); + % Wartoœci dla TRZECIEGO stopnia +% Fp3 = min(0.4/L3,0.4/M3)*(fold*L1/M1*L2/M2*L3); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci fold*L1/M1*L2 + Fs3 = min(0.5/L3,0.5/M3)*(fold*L1/M1*L2/M2*L3); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1/M1*L2 + Fp3 = (1-Fp_factor)*Fs3; + % alias jest dopuszczalny do szybkoœci Fmax + if (Fs3 >= Fmax), + Fs3 = Fs3 + (Fs3-Fmax); + end + if (Fp3 >= Fp), + Fp3 = Fp; % wybieramy szersze pasmo przejœciowe + else + disp('Fp3 < Fp'); + end + if (Fs3 < Fmax) + disp('Fs3 < Fmax'); + end + fp3 = Fp3/(fold*L1/M1*L2/M2*L3); fs3 = Fs3/(fold*L1/M1*L2/M2*L3); + Fmax3 = min(Fmax2, Fs3); + if (Fmax3 < Fmax) + disp('Fmax3 < Fmax'); + end + +% fp4 = (min(0.4/L,0.4/M)*fnew)/(fold*L1*L2*L3*L4/(M1*M2*M3)) +% fs4 = (min(0.5/L,0.5/M)*fnew)/(fold*L1*L2*L3*L4/(M1*M2*M3)) + % Wartoœci dla czwartego stopnia +% Fp4 = min(0.4/L4,0.4/M4)*(fold*L1/M1*L2/M2*L3/M3*L4); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci fold*L1/M1*L2 + Fs4 = min(0.5/L4,0.5/M4)*(fold*L1/M1*L2/M2*L3/M3*L4); % filtr dla pierwszego stopnia pracuje na czêstotliwoœci Fold*L1/M1*L2 + Fp4 = (1-Fp_factor)*Fs4; + % alias jest dopuszczalny do szybkoœci Fmax + if (Fs4 >= Fmax), + Fs4 = Fs4 + (Fs4-Fmax); + end + if (Fp4 >= Fp), + Fp4 = Fp; % wybieramy szersze pasmo przejœciowe + else + disp('Fp4 < Fp'); + end + if (Fs4 < Fmax) + disp('Fs4 < Fmax'); + end + fp4 = Fp4/(fold*L1/M1*L2/M2*L3/M3*L4); fs4 = Fs4/(fold*L1/M1*L2/M2*L3/M3*L4); + Fmax4 = min(Fmax3, Fs4); + if (Fmax4 < Fmax) + set(txtFmax2, 'String', sprintf('F_max = %.1f [Hz]', Fmax4), 'ForegroundColor', 'red', 'FontWeight', 'Bold'); + else + set(txtFmax2, 'String', sprintf('F_max = %.1f [Hz]', Fmax4), 'ForegroundColor', 'black', 'FontWeight', 'normal'); + end + + set(edtFP1, 'String', fp1); + set(edtFS1, 'String', fs1); + set(edtFP2, 'String', fp2); + set(edtFS2, 'String', fs2); + set(edtFP3, 'String', fp3); + set(edtFS3, 'String', fs3); + set(edtFP4, 'String', fp4); + set(edtFS4, 'String', fs4); +end + +end + + +function WyborStopni(hObject, eventdata) + +set(edtL1, 'Enable', 'off'); +set(edtM1, 'Enable', 'off'); +set(edtFP1, 'Enable', 'off'); +set(edtFS1, 'Enable', 'off'); + +set(edtL2, 'Enable', 'off'); +set(edtM2, 'Enable', 'off'); +set(edtFP2, 'Enable', 'off'); +set(edtFS2, 'Enable', 'off'); + +set(edtL3, 'Enable', 'off'); +set(edtM3, 'Enable', 'off'); +set(edtFP3, 'Enable', 'off'); +set(edtFS3, 'Enable', 'off'); + +set(edtL4, 'Enable', 'off'); +set(edtM4, 'Enable', 'off'); +set(edtFP4, 'Enable', 'off'); +set(edtFS4, 'Enable', 'off'); + +set(edtL1, 'String', ''); +set(edtM1, 'String', ''); +set(edtFP1, 'String', ''); +set(edtFS1, 'String', ''); + +set(edtL2, 'String', ''); +set(edtM2, 'String', ''); +set(edtFP2, 'String', ''); +set(edtFS2, 'String', ''); + +set(edtL3, 'String', ''); +set(edtM3, 'String', ''); +set(edtFP3, 'String', ''); +set(edtFS3, 'String', ''); + +set(edtL4, 'String', ''); +set(edtM4, 'String', ''); +set(edtFP4, 'String', ''); +set(edtFS4, 'String', ''); + +ile_stopni = get(hObject, 'Value'); + +if (ile_stopni > 0) +set(edtL1, 'Enable', 'on'); +set(edtM1, 'Enable', 'on'); +set(edtFP1, 'Enable', 'on'); +set(edtFS1, 'Enable', 'on'); +end + +if (ile_stopni > 1) +set(edtL2, 'Enable', 'on'); +set(edtM2, 'Enable', 'on'); +set(edtFP2, 'Enable', 'on'); +set(edtFS2, 'Enable', 'on'); + end + + if (ile_stopni > 2) + set(edtL3, 'Enable', 'on'); + set(edtM3, 'Enable', 'on'); + set(edtFP3, 'Enable', 'on'); + set(edtFS3, 'Enable', 'on'); + end + + if (ile_stopni > 3) + set(edtL4, 'Enable', 'on'); + set(edtM4, 'Enable', 'on'); + set(edtFP4, 'Enable', 'on'); + set(edtFS4, 'Enable', 'on'); + end + + end + + + + function Nnum = ObliczNnum(Ni, Li, Mi) + stopien = length(Ni); + + if (stopien >= 1), FLPFi(1) = fold * Li(1); end + if (stopien >= 2), FLPFi(2) = fold * Li(1) * Li(2) / Mi(1); end + if (stopien >= 3), FLPFi(3) = fold * Li(1) * Li(2) * Li(3) / (Mi(1) * Mi(2)); end + if (stopien >= 4), FLPFi(4) = fold * Li(1) * Li(2) * Li(3) * Li(4) / (Mi(1) * Mi(2) * Mi(3)); end + + Nnum = sum(Ni .* FLPFi) / fnew; + Nnum = ceil(Nnum); + end + + + + function Start(hObject, eventdata) + + set(txtN1, 'String', ''); + set(txtN2, 'String', ''); + set(txtN3, 'String', ''); + set(txtN4, 'String', ''); + set(txtNtot, 'String', ''); + set(txtNnum, 'String', ''); + drawnow; + + for i = 2:7 + if ishandle(i) + close(i); + end + end + + if (ile_stopni == 1) + L1 = str2double(get(edtL1, 'String')); + M1 = str2double(get(edtM1, 'String')); + + FP1 = str2double(get(edtFP1, 'String')); + FS1 = str2double(get(edtFS1, 'String')); + + Li = L1; + Mi = M1; + + FPi = FP1; + FSi = FS1; + + if isnan(L1) || isnan(M1) || isnan(FP1) || isnan(FS1) || ~is_calkowita(L1) || ~is_calkowita(M1) + msgbox('Nieprawid³owa wartoœæ w Li, Mi, FPi lub FSi.', 'B³¹d'); + return; + end + + if FP1 >= FS1 + msgbox('FSi musi byc wiêksze od FPi', 'B³¹d'); + return; + end + + if prod(Li) ~= L || prod(Mi) ~= M + msgbox('Iloczyn Li (Mi) musi byæ równy L (M).', 'B³¹d'); + return; + end + + N = id_1(nr_sygnalu, fold, fnew, Li, Mi, FPi, FSi); + set(txtN1, 'String', sprintf('N1 = %d', N(1))); + end + + if (ile_stopni == 2) + L1 = str2double(get(edtL1, 'String')); + M1 = str2double(get(edtM1, 'String')); + M2 = str2double(get(edtM2, 'String')); + L2 = str2double(get(edtL2, 'String')); + + FP1 = str2double(get(edtFP1, 'String')); + FS1 = str2double(get(edtFS1, 'String')); + FP2 = str2double(get(edtFP2, 'String')); + FS2 = str2double(get(edtFS2, 'String')); + + Li = [ L1, L2 ]; + Mi = [ M1, M2 ]; + + FPi = [ FP1, FP2 ]; + FSi = [ FS1, FS2 ]; + + if isnan(L1) || isnan(M1) || isnan(FP1) || isnan(FS1) || ~is_calkowita(L1) || ~is_calkowita(M1) ||... + isnan(L2) || isnan(M2) || isnan(FP2) || isnan(FS2) || ~is_calkowita(L2) || ~is_calkowita(M2) + msgbox('Nieprawid³owa wartoœæ w Li, Mi, FPi lub FSi.', 'B³¹d'); + return; + end + + if FP1 >= FS1 || FP2 >= FS2 + msgbox('FSi musi byc wiêksze od FPi', 'B³¹d'); + return; + end + + if prod(Li) ~= L || prod(Mi) ~= M + msgbox('Iloczyn Li (Mi) musi byæ równy L (M).', 'B³¹d'); + return; + end + + N = id_2(nr_sygnalu, fold, fnew, Li, Mi, FPi, FSi); + + set(txtN1, 'String', sprintf('N1 = %d', N(1))); + set(txtN2, 'String', sprintf('N2 = %d', N(2))); + end + + if (ile_stopni == 3) + L1 = str2double(get(edtL1, 'String')); + M1 = str2double(get(edtM1, 'String')); + L2 = str2double(get(edtL2, 'String')); + M2 = str2double(get(edtM2, 'String')); + L3 = str2double(get(edtL3, 'String')); + M3 = str2double(get(edtM3, 'String')); + + FP1 = str2double(get(edtFP1, 'String')); + FS1 = str2double(get(edtFS1, 'String')); + FP2 = str2double(get(edtFP2, 'String')); + FS2 = str2double(get(edtFS2, 'String')); + FP3 = str2double(get(edtFP3, 'String')); + FS3 = str2double(get(edtFS3, 'String')); + + Li = [ L1, L2, L3 ]; + Mi = [ M1, M2, M3 ]; + + FPi = [ FP1, FP2, FP3 ]; + FSi = [ FS1, FS2, FS3 ]; + + if isnan(L1) || isnan(M1) || isnan(FP1) || isnan(FS1) || ~is_calkowita(L1) || ~is_calkowita(M1) ||... + isnan(L2) || isnan(M2) || isnan(FP2) || isnan(FS2) || ~is_calkowita(L2) || ~is_calkowita(M2) ||... + isnan(L3) || isnan(M3) || isnan(FP3) || isnan(FS3) || ~is_calkowita(L3) || ~is_calkowita(M3) + msgbox('Nieprawid³owa wartoœæ w Li, Mi, FPi lub FSi.', 'B³¹d'); + return; + end + + if FP1 >= FS1 || FP2 >= FS2 || FP3 >= FS3 + msgbox('FSi musi byc wiêksze od FPi', 'B³¹d'); + return; + end + + if prod(Li) ~= L || prod(Mi) ~= M + msgbox('Iloczyn Li (Mi) musi byæ równy L (M).', 'B³¹d'); + return; + end + + N = id_3(nr_sygnalu, fold, fnew, Li, Mi, FPi, FSi); + + set(txtN1, 'String', sprintf('N1 = %d', N(1))); + set(txtN2, 'String', sprintf('N2 = %d', N(2))); + set(txtN3, 'String', sprintf('N3 = %d', N(3))); + end + + if (ile_stopni == 4) + L1 = str2double(get(edtL1, 'String')); + M1 = str2double(get(edtM1, 'String')); + L2 = str2double(get(edtL2, 'String')); + M2 = str2double(get(edtM2, 'String')); + L3 = str2double(get(edtL3, 'String')); + M3 = str2double(get(edtM3, 'String')); + L4 = str2double(get(edtL4, 'String')); + M4 = str2double(get(edtM4, 'String')); + + FP1 = str2double(get(edtFP1, 'String')); + FS1 = str2double(get(edtFS1, 'String')); + FP2 = str2double(get(edtFP2, 'String')); + FS2 = str2double(get(edtFS2, 'String')); + FP3 = str2double(get(edtFP3, 'String')); + FS3 = str2double(get(edtFS3, 'String')); + FP4 = str2double(get(edtFP4, 'String')); + FS4 = str2double(get(edtFS4, 'String')); + + Li = [ L1, L2, L3, L4 ]; + Mi = [ M1, M2, M3, M4 ]; + + FPi = [ FP1, FP2, FP3, FP4 ]; + FSi = [ FS1, FS2, FS3, FS4 ]; + + if isnan(L1) || isnan(M1) || isnan(FP1) || isnan(FS1) || ~is_calkowita(L1) || ~is_calkowita(M1) ||... + isnan(L2) || isnan(M2) || isnan(FP2) || isnan(FS2) || ~is_calkowita(L2) || ~is_calkowita(M2) ||... + isnan(L3) || isnan(M3) || isnan(FP3) || isnan(FS3) || ~is_calkowita(L3) || ~is_calkowita(M3) ||... + isnan(L4) || isnan(M4) || isnan(FP4) || isnan(FS4) || ~is_calkowita(L4) || ~is_calkowita(M4) + msgbox('Nieprawid³owa wartoœæ w Li, Mi, FPi lub FSi.', 'B³¹d'); + return; + end + + if FP1 >= FS1 || FP2 >= FS2 || FP3 >= FS3 || FP4 >= FS4 + msgbox('FSi musi byc wiêksze od FPi', 'B³¹d'); + return; + end + + if prod(Li) ~= L || prod(Mi) ~= M + msgbox('Iloczyn Li (Mi) musi byæ równy L (M).', 'B³¹d'); + return; + end + + N = id_4(nr_sygnalu, fold, fnew, Li, Mi, FPi, FSi); + + set(txtN1, 'String', sprintf('N1 = %d', N(1))); + set(txtN2, 'String', sprintf('N2 = %d', N(2))); + set(txtN3, 'String', sprintf('N3 = %d', N(3))); + set(txtN4, 'String', sprintf('N4 = %d', N(4))); + end + + Ntot = sum(N); + Nnum = ObliczNnum(N, Li, Mi); + + set(txtNtot, 'String', sprintf('Ntot = %d', Ntot)); + set(txtNnum, 'String', sprintf('Nnum = %d', Nnum)); + + end + + + +screen_resolution = get(0, 'ScreenSize'); +screen_width = screen_resolution(3); +screen_height = screen_resolution(4); + +window_width = 427; +window_height = 525+40; + +window_position = [(screen_width/2 - window_width/2),... + (screen_height/2 - window_height/2),... + window_width,... + window_height]; + +main = figure('Name','Konwersja szybkoœci próbkowania (ver.2)',... + 'NumberTitle','off',... + 'Resize','off',... + 'Visible','on',... + 'MenuBar', 'none',... + 'DoubleBuffer', 'on',... + 'units', 'pixels',... + 'color', [.9 .9 .9],... + 'KeyPressFcn', @keyPress,... + 'Position', window_position,... + 'tag', 'MultiSRC_gui_v2'); + + + +panel1 = uipanel('Parent', main, 'Units', 'pixels', 'Visible', 'on', 'Position', [5 320+40 420 200]); + +txtL = uicontrol('Parent', panel1, 'Style', 'text', 'String', 'L = ', 'Position', [10 35 150 30], 'FontSize', 12, 'FontWeight', 'Bold'); +txtM = uicontrol('Parent', panel1, 'Style', 'text', 'String', 'M = ', 'Position', [210 35 150 30], 'FontSize', 12, 'FontWeight', 'Bold'); +txtFmax = uicontrol('Parent', panel1, 'Style', 'text', 'String', 'F_max = ', 'Position', [70 15 170 20], 'FontSize', 12, 'HorizontalAlignment', 'left'); + +uicontrol('Parent', panel1, 'Style', 'pushbutton', 'String', 'Odœwie¿', 'FontName', 'Times New Roman CE', 'Position', [120 70 150 30], 'Callback', @Odswiez); + +uicontrol('Parent', panel1, 'Style', 'text', 'String', 'F_in = [Sa/S]', 'Position', [10 120 150 15], 'HorizontalAlignment', 'left'); +edtFold = uicontrol('Parent', panel1, 'Style', 'edit', 'String', '', 'Position', [85 115 65 25], 'BackgroundColor', 'white', 'HorizontalAlignment', 'left'); + +uicontrol('Parent', panel1, 'Style', 'text', 'String', 'F_out = [Sa/S]', 'Position', [210 120 150 15], 'HorizontalAlignment', 'left'); +edtFnew = uicontrol('Parent', panel1, 'Style', 'edit', 'String', '', 'Position', [295 115 65 25], 'BackgroundColor', 'white', 'HorizontalAlignment', 'left'); + +uicontrol('Parent', panel1, 'Style', 'text', 'String', 'SYGNA£ TESTOWY', 'FontName', 'Times New Roman CE', 'Position', [80 160 100 15], 'HorizontalAlignment', 'left'); +uicontrol('Parent', panel1, 'Style', 'popupmenu', 'String', {'Sygna³ 1', 'Sygna³ 2'}, 'FontName', 'Times New Roman CE', 'Position', [190 160 100 20], 'Callback', @WyborSygnalu, 'BackgroundColor', 'white'); + +uicontrol('Parent', panel1, 'Style', 'pushbutton', 'String', 'POMOC [F11]', 'Position', [330 155 80 30], 'Callback', @Help); + +panel2 = uipanel('Parent', main, 'Units', 'pixels', 'Visible', 'on', 'Position', [5 155 420 160+40]); + +uicontrol('Parent', panel2, 'Style', 'text', 'String', 'L4 = ', 'Position', [10 15+40 25 15], 'HorizontalAlignment', 'left'); +edtL4 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [40 10+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); +uicontrol('Parent', panel2, 'Style', 'text', 'String', 'M4 = ', 'Position', [110 15+40 25 15], 'HorizontalAlignment', 'left'); +edtM4 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [140 10+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); +uicontrol('Parent', panel2, 'Style', 'text', 'String', '<fp,fs> LPF4 < , >', 'Position', [210 15+40 200 15], 'HorizontalAlignment', 'left'); +edtFP4 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [290 10+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); +edtFS4 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [350 10+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); + +uicontrol('Parent', panel2, 'Style', 'text', 'String', 'L3 = ', 'Position', [10 40+40 25 15], 'HorizontalAlignment', 'left'); +edtL3 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [40 35+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); +uicontrol('Parent', panel2, 'Style', 'text', 'String', 'M3 = ', 'Position', [110 40+40 25 15], 'HorizontalAlignment', 'left'); +edtM3 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [140 35+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); +uicontrol('Parent', panel2, 'Style', 'text', 'String', '<fp,fs> LPF3 < , >', 'Position', [210 40+40 200 15], 'HorizontalAlignment', 'left'); +edtFP3 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [290 35+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); +edtFS3 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [350 35+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); + +uicontrol('Parent', panel2, 'Style', 'text', 'String', 'L2 = ', 'Position', [10 65+40 25 15], 'HorizontalAlignment', 'left'); +edtL2 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [40 60+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); +uicontrol('Parent', panel2, 'Style', 'text', 'String', 'M2 = ', 'Position', [110 65+40 25 15], 'HorizontalAlignment', 'left'); +edtM2 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [140 60+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); +uicontrol('Parent', panel2, 'Style', 'text', 'String', '<fp,fs> LPF2 < , >', 'Position', [210 65+40 200 15], 'HorizontalAlignment', 'left'); +edtFP2 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [290 60+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); +edtFS2 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [350 60+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'off'); + +uicontrol('Parent', panel2, 'Style', 'text', 'String', 'L1 = ', 'Position', [10 90+40 25 15], 'HorizontalAlignment', 'left'); +edtL1 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [40 85+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'on'); +uicontrol('Parent', panel2, 'Style', 'text', 'String', 'M1 = ', 'Position', [110 90+40 25 15], 'HorizontalAlignment', 'left'); +edtM1 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [140 85+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'on'); +uicontrol('Parent', panel2, 'Style', 'text', 'String', '<fp,fs> LPF1 < , >', 'Position', [210 90+40 200 15], 'HorizontalAlignment', 'left'); +edtFP1 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [290 85+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'on'); +edtFS1 = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '', 'Position', [350 85+40 50 25], 'HorizontalAlignment', 'left', 'BackgroundColor', 'white', 'Enable', 'on'); + +uicontrol('Parent', panel2, 'Style', 'text', 'String', 'LICZBA STOPNI', 'Position', [15 130+40 100 15], 'HorizontalAlignment', 'left'); +uicontrol('Parent', panel2, 'Style', 'popupmenu', 'String', {'1', '2', '3', '4'}, 'Position', [100 130+40 50 20], 'Callback', @WyborStopni, 'BackgroundColor', 'white'); +uicontrol('Parent', panel2, 'Style', 'text', 'String', 'alfa = ', 'Position', [160 130+40 40 15], 'HorizontalAlignment', 'right'); +edtFp_factor = uicontrol('Parent', panel2, 'Style', 'edit', 'String', '0.2', 'Position', [205 125+40 50 25], 'BackgroundColor', 'white', 'HorizontalAlignment', 'left'); +uicontrol('Parent', panel2, 'Style', 'pushbutton', 'String', 'Wylicz fp i fs', 'Position', [290 122+40 110 30], 'Callback', @WyliczDomyslneFsFp); + +txtFmax2 = uicontrol('Parent', panel2, 'Style', 'text', 'String', '', 'Position', [70 15 170 20], 'FontSize', 12, 'HorizontalAlignment', 'left'); + + +panel3 = uipanel('Parent', main, 'Units', 'pixels', 'Visible', 'on', 'Position', [5 5 420 145]); + +txtN1 = uicontrol('Parent', panel3, 'Style', 'text', 'String', '', 'Position', [10 50 100 30], 'FontSize', 12, 'FontWeight', 'Bold'); +txtN2 = uicontrol('Parent', panel3, 'Style', 'text', 'String', '', 'Position', [110 50 100 30], 'FontSize', 12, 'FontWeight', 'Bold'); +txtN3 = uicontrol('Parent', panel3, 'Style', 'text', 'String', '', 'Position', [210 50 100 30], 'FontSize', 12, 'FontWeight', 'Bold'); +txtN4 = uicontrol('Parent', panel3, 'Style', 'text', 'String', '', 'Position', [310 50 100 30], 'FontSize', 12, 'FontWeight', 'Bold'); + +txtNtot = uicontrol('Parent', panel3, 'Style', 'text', 'String', '', 'Position', [ 35 10 150 30], 'FontSize', 12, 'FontWeight', 'Bold'); +txtNnum = uicontrol('Parent', panel3, 'Style', 'text', 'String', '', 'Position', [235 10 150 30], 'FontSize', 12, 'FontWeight', 'Bold'); + +uicontrol('Parent', panel3, 'Style', 'pushbutton', 'String', 'START', 'Position', [50 100 100 30], 'Callback', @Start); +uicontrol('Parent', panel3, 'Style', 'text', 'String', 'uruchom zmianê szybkoœci próbkowania', 'FontName', 'Times New Roman CE', 'Position', [160 100 250 20], 'HorizontalAlignment', 'left'); + + + +nr_sygnalu = 1; +ile_stopni = 1; + +end + diff --git a/Ex3/matlab/SPECgraf.m b/Ex3/matlab/SPECgraf.m new file mode 100644 index 0000000000000000000000000000000000000000..d892ec7febd085494a1abaf1f3c254b455018b45 --- /dev/null +++ b/Ex3/matlab/SPECgraf.m @@ -0,0 +1,1436 @@ +function varargout = SPECgraf(Akcja, param) +%cos(cumsum(n/1000)) + +% \fixed 2017.03.22 psd ==> pwelch +% \fixed 2012.03.05 finite ==> isfinite +% \fixed 2006.10.11 dealt with LineStyle/Marker warning +% \fixed 2005.11.20 dealt with "Warning: Log of zero." in ylim evaluation +% \fixed 2005.11.20 Placed all in single file +% \fixed 2005.11.20 Fixed problems with zoom out + +if nargin == 0 % LAUNCH GUI + +% fig = openfig(mfilename,'reuse'); return; %ZapiszFig(1,'specGUI.m') + if isempty(findobj(0, 'tag', 'Specgraf_DrawFig')) + + fig = Specgraf_DrawFig; + set(fig,'tag', 'Specgraf_DrawFig', 'Units', 'pixels'); + set(fig,'name', 'Spektrogram sygna³ów niestacjonarnych (2017.03.22) dr in¿. Marek Blok)',... + 'KeyPressFcn','1;'); + + SPECgraf('Init'); + SPECgraf('signal'); + set(fig,'Visible','on'); +% SPECgraf('per'); + else + SPECgraf('Exit'); + end + return; +end; + +if ~isstr(Akcja) % INVOKE NAMED SUBFUNCTION OR CALLBACK + disp('Something''s wrong'); + return; +end; + +% Generate a structure of handles to pass to callbacks, and store it. +fig=findobj(0, 'tag', 'Specgraf_DrawFig'); +hEditN=findobj(fig,'tag', 'N_edit'); +hEditM=findobj(fig,'tag', 'M_edit'); +hEditL=findobj(fig,'tag', 'L_edit'); +hEditK=findobj(fig,'tag', 'K_edit'); +hEditO=findobj(fig,'tag', 'O_edit'); +hEditW=findobj(fig,'tag', 'w_edit'); +hEditX=findobj(fig,'tag', 'x_edit'); +h_real=findobj(fig,'tag', 'real_checkbox'); +h_dB=findobj(fig,'tag', 'dB_checkbox'); +hEditNoise=findobj(fig,'tag', 'Noise_edit'); +hEditName=findobj(fig,'tag', 'Name_edit'); +hMenu=findobj(fig,'tag', 'choose_popupmenu'); +h_det=findobj(fig,'tag', 'detrend_checkbox'); +ha=get(fig, 'UserData'); +Ktory=get(hMenu,'Value'); +hEdit_dY=findobj(fig,'tag', 'dY_edit'); + +if strcmp(Akcja, 'Exit') + close(fig); + return; +elseif strcmp(Akcja, 'Init') + set(hEditX,'UserData','randn(1,L)'); + set(hEditX,'String','randn(1,L)'); + set(hEditX,'Max', 2); + + set(hEditW,'UserData','boxcar(M)'); + set(hEditW,'String','boxcar(M)'); + + set(hEditL,'UserData','1000'); + set(hEditL,'String','1000'); + set(hEditM,'UserData','100'); + set(hEditM,'String','100'); + set(hEditNoise,'UserData','-100'); + set(hEditNoise,'String','-100'); + +% set(hEditN,'UserData','1'); +% set(hEditN,'String','1'); + set(hEditO,'UserData','0'); + set(hEditO,'String','0'); + + set(hEditK,'UserData','256'); + set(hEditK,'String','256'); + + set(hEditName,'String','new'); + set(hMenu,'String','new'); + + set(h_real,'UserData',1); + set(h_real,'Value',1); + + set(h_dB,'UserData',0); + set(h_dB,'Value',0); + + set(h_det,'UserData',1); + set(h_det,'Value',1); + + ha(1)=findobj(fig,'tag', 'Signal_re_axes'); + ha(2)=findobj(fig,'tag', 'Signal_im_axes'); + ha(3)=findobj(fig,'tag', 'spec_axes'); + ha(4)=findobj(fig,'tag', 'per_axes'); +% for ind=[1 2 4], axes(ha(ind)); zoom on; end; +% axes(ha(3)); zoom off; + + set(fig, 'UserData', ha); + + set(hMenu,'UserData', [NaN, NaN, NaN, NaN, NaN, NaN, NaN, 1, -100, 5, -100, 5]); %handles & maximal values + set(hEdit_dY,'String','120'); + return; +elseif strcmp(Akcja, 'change_name') + pom=get(hMenu,'String'); + pom2=get(hEditName,'String'); + pom(Ktory,1:length(pom2)+1)=[pom2 0]; + set(hMenu,'String',pom); + set(hMenu, 'Value', Ktory); + return; +elseif strcmp(Akcja, 'new') + pom=get(hMenu,'String'); + Ktory=size(pom,1)+1; + pom(Ktory,1:4)=['new' 0]; + set(hMenu,'String',pom); + + + pom=get(hEditX,'UserData'); + pom(Ktory,1:11)=['randn(1,L)' 0]; + set(hEditX,'UserData',pom); + pom=get(hEditW,'UserData'); + pom(Ktory,1:10)=['boxcar(M)' 0]; + set(hEditW,'UserData',pom); + + pom=get(hEditL,'UserData'); + pom(Ktory,1:4)=['100' 0]; + set(hEditL,'UserData',pom); + pom=get(hEditM,'UserData'); + pom(Ktory,1:4)=['100' 0]; + set(hEditM,'UserData',pom); + pom=get(hEditNoise,'UserData'); + pom(Ktory,1:5)=['-100' 0]; + set(hEditNoise,'UserData',pom); + +% pom=get(hEditN,'UserData'); +% pom(Ktory,1:2)=['1' 0]; +% set(hEditN,'UserData',pom); + pom=get(hEditO,'UserData'); + pom(Ktory,1:2)=['0' 0]; + set(hEditO,'UserData',pom); + + pom=get(hEditK,'UserData'); + pom(Ktory,1:5)=['256' 0]; + set(hEditK,'UserData',pom); + + pom=get(hMenu,'UserData'); + pom(Ktory,1:size(pom,2))=ones(1,size(pom,2))*NaN; + set(hMenu,'UserData',pom); + + pom=get(h_real,'UserData'); + pom(Ktory,1)=1; + set(h_real,'Value', pom(Ktory,1)); + set(h_real,'UserData',pom); + + pom=get(h_det,'UserData'); + pom(Ktory,1)=1; + set(h_det,'Value', pom(Ktory,1)); + set(h_det,'UserData',pom); + + set(hMenu,'Value', Ktory); + + SPECgraf('Choose'); + SPECgraf('signal', Ktory); + return; +elseif strcmp(Akcja, 'delete') + pom=get(hMenu,'String'); + if size(pom,1)==1, + %SPECgraf('Reset'); + return; + end; + pom(Ktory,:)=[]; + set(hMenu,'String',pom); + + + pom=get(hEditX,'UserData'); + pom(Ktory,:)=[]; + set(hEditX,'UserData',pom); + pom=get(hEditW,'UserData'); + pom(Ktory,:)=[]; + set(hEditW,'UserData',pom); + + pom=get(hEditL,'UserData'); + pom(Ktory,:)=[]; + set(hEditL,'UserData',pom); + pom=get(hEditM,'UserData'); + pom(Ktory,:)=[]; + set(hEditM,'UserData',pom); + pom=get(hEditNoise,'UserData'); + pom(Ktory,:)=[]; + set(hEditNoise,'UserData',pom); + +% pom=get(hEditN,'UserData'); +% pom(Ktory,:)=[]; +% set(hEditN,'UserData',pom); + pom=get(hEditO,'UserData'); + pom(Ktory,:)=[]; + set(hEditO,'UserData',pom); + + pom=get(hEditK,'UserData'); + pom(Ktory,:)=[]; + set(hEditK,'UserData',pom); + + pom=get(hMenu,'UserData'); + for ind=1:3, + if isfinite(pom(Ktory,ind)) + delete(pom(Ktory,ind)); + end + end + pom(Ktory,:)=[]; + set(hMenu,'UserData',pom); + + pom=get(h_real,'UserData'); + pom(Ktory,:)=[]; + set(h_real,'UserData',pom); + + pom=get(h_det,'UserData'); + pom(Ktory,:)=[]; + set(h_det,'UserData',pom); + + set(hMenu,'Value', 1); + +% SPECgraf('signal', Ktory); + SPECgraf('Choose'); + return; + + +elseif strcmp(Akcja, 'Choose') + %selected new filter response + pom=get(hMenu,'String'); + ind=find(pom(Ktory,:)==0); + if isempty(ind) + ind=size(pom,2); + else + ind=ind(1)-1; + end + set(hEditName,'String',pom(Ktory,1:ind)); + + pom=get(hEditX,'UserData'); + set(hEditX, 'String', pom(Ktory,:)); + pom=get(hEditW,'UserData'); + set(hEditW, 'String', pom(Ktory,:)); + + pom=get(hEditL,'UserData'); + set(hEditL, 'String', pom(Ktory,:)); + pom=get(hEditM,'UserData'); + set(hEditM, 'String', pom(Ktory,:)); + pom=get(hEditNoise,'UserData'); + set(hEditNoise, 'String', pom(Ktory,:)); + +% pom=get(hEditN,'UserData'); +% set(hEditN, 'String', pom(Ktory,:)); + pom=get(hEditO,'UserData'); + set(hEditO, 'String', pom(Ktory,:)); + + pom=get(hEditK,'UserData'); + set(hEditK, 'String', pom(Ktory,:)); + + pom=get(h_real,'UserData'); + set(h_real,'Value', pom(Ktory,1)); + + pom=get(h_det,'UserData'); + set(h_det,'Value', pom(Ktory,1)); + +% SPECgraf('signal', Ktory); + return; + +elseif strcmp(Akcja, 'signal') + if nargin==2, + Ktory=param; + else + %save strings + tekst=[get(hEditL, 'String') 0]; + pom=get(hEditL,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditL,'UserData', setstr(pom)); + + tekst=[get(hEditNoise, 'String') 0]; + pom=get(hEditNoise,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditNoise,'UserData', setstr(pom)); + + tekst=get(hEditX, 'String').'; + tekst=[tekst(:); 0].'; + pom=get(hEditX,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditX,'UserData', setstr(pom)); + + tekst=get(h_real, 'Value'); + pom=get(h_real,'UserData'); + pom(Ktory,1)=tekst; + set(h_real,'UserData', pom); + end; + + pom=get(hMenu,'UserData'); + hp_re=pom(:,1); + hp_im=pom(:,2); + hp_spec_t=pom(:,3); + hp_spec_t2=pom(:,4); + hp_spec=pom(:,5); + hp_per=pom(:,6); + hp_per2=pom(:,7); + max_x=pom(:,8); + min_spec=pom(:,9); + max_spec=pom(:,10); + min_per=pom(:,11); + max_per=pom(:,12); + + %generate signal + tekstL=get(hEditL,'UserData'); tekstL=tekstL(Ktory,:); + ind=find(tekstL==0); + if ~isempty(ind) + tekstL=tekstL(1:ind(1)-1); + end; + eval(['L=' tekstL ';'], 'L=1;') + + n=0:L-1; + tekstX=get(hEditX,'UserData'); tekstX=tekstX(Ktory,:); + ind=find(tekstX==0); + if ~isempty(ind) + tekstX=tekstX(1:ind(1)-1); + end; + eval(['x=' tekstX ';'], 'x=zeros(1,L);') + + Re=get(h_real,'UserData'); Re=Re(Ktory,1); + + tekstNoise=get(hEditNoise,'UserData'); tekstNoise=tekstNoise(Ktory,:); + ind=find(tekstNoise==0); + if ~isempty(ind) + tekstNoise=tekstNoise(1:ind(1)-1); + end; + eval(['Noise=' tekstNoise ';'], 'Noise=-300;') + + x=x(:); + if length(x)<L; + x(L)=0; + else + x=x(1:L); + end; + + N_lin=10.^(Noise/20); + if Re==1 + x=real(x)+N_lin*randn(size(x)); + else + x=x+N_lin*(randn(size(x))+j*randn(size(x)))/sqrt(2); + end; + max_x(Ktory)=max(abs([real(x); imag(x)])); + + %draw signal + + %real part of the signal + axes(ha(1)); + if isnan(hp_re(Ktory)) + hold on; + hp_re(Ktory)=plot(n,real(x), 'Color', 'b'); + hold off; + else + set(hp_re(Ktory),'Xdata', n, 'Ydata', real(x)); + end +% set(ha(1), 'Xlim', [-0.5, L-0.5], 'Ylim', [-1.1 1.1]*max(max_x)); +% eval('zoom reset', 'set(get(ha(1),''ZLabel''),''UserData'',[]);'); +% reset(get(ha(1),'ZLabel')); + + %imaginary part of the signal +% axes(ha(2)); + if isnan(hp_im(Ktory)) + hold on; + hp_im(Ktory)=plot(n,imag(x), 'Color', 'r'); + hold off; + else + set(hp_im(Ktory),'Xdata', n, 'Ydata', imag(x)); + end + set(ha(1), 'Xlim', [-0.5, L-0.5], 'Ylim', [-1.1 1.1]*max(max_x)); +% set(get(ha(2),'ZLabel'),'UserData',[]); +% reset(get(ha(2),'ZLabel')); +% eval('zoom reset', 'set(get(ha(1),''ZLabel''),''UserData'',[]);'); + if L>512 + set([hp_re, hp_im], 'Marker', '.', 'MarkerSize', 4); + else + set([hp_re, hp_im], 'LineStyle', '-'); + end; + eval('rmappdata(get(ha(1),''Zlabel''),''ZOOMAxesData'')','set(get(ha(1),''ZLabel''),''UserData'',[])'); + + set(hMenu,'UserData', [hp_re, hp_im, hp_spec_t, hp_spec_t2, hp_spec, hp_per, hp_per2, max_x, min_spec, max_spec, min_per, max_per]); + + %compute and draw periodogram + SPECgraf('spec', Ktory) +% SPECgraf zoom_on; + return; + +elseif strcmp(Akcja, 'spec') + if nargin==2, + Ktory=param; + else + %save strings + tekst=[get(hEditK, 'String') 0]; + pom=get(hEditK,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditK,'UserData', setstr(pom)); + + tekst=[get(hEditM, 'String') 0]; + pom=get(hEditM,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditM,'UserData', setstr(pom)); + +% tekst=[get(hEditN, 'String') 0]; +% pom=get(hEditN,'UserData'); +% pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... +% zeros(1, max([1; size(pom,2); length(tekst)])); +% pom(Ktory,1:length(tekst))=tekst; +% set(hEditN,'UserData', setstr(pom)); + + tekst=[get(hEditO, 'String') 0]; + pom=get(hEditO,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditO,'UserData', setstr(pom)); + + tekst=[get(hEditW, 'String') 0]; + pom=get(hEditW,'UserData'); + pom(Ktory,1:max([1; size(pom,2); length(tekst)]))= ... + zeros(1, max([1; size(pom,2); length(tekst)])); + pom(Ktory,1:length(tekst))=tekst; + set(hEditW,'UserData', setstr(pom)); + + tekst=get(h_det, 'Value'); + pom=get(h_det,'UserData'); + pom(Ktory,1)=tekst; + set(h_det,'UserData', pom); + end; + + pom=get(hMenu,'UserData'); + hp_re=pom(:,1); + hp_im=pom(:,2); + hp_spec_t=pom(:,3); + hp_spec_t2=pom(:,4); + hp_spec=pom(:,5); + hp_per=pom(:,6); + hp_per2=pom(:,7); + max_x=pom(:,8); + min_spec=pom(:,9); + max_spec=pom(:,10); + min_per=pom(:,11); + max_per=pom(:,12); + + %generate signal + tekstK=get(hEditK,'UserData'); tekstK=tekstK(Ktory,:); + ind=find(tekstK==0); + if ~isempty(ind) + tekstK=tekstK(1:ind(1)-1); + end; + eval(['K=' tekstK ';'], 'K=16;') + + tekstM=get(hEditM,'UserData'); tekstM=tekstM(Ktory,:); + ind=find(tekstM==0); + if ~isempty(ind) + tekstM=tekstM(1:ind(1)-1); + end; + eval(['M=' tekstM ';'], 'M=16;') + if M>K + M=K; + set(hEditM,'String', num2str(M)); + end; + +% tekstN=get(hEditN,'UserData'); tekstN=tekstN(Ktory,:); +% ind=find(tekstN==0); +% if ~isempty(ind) +% tekstN=tekstN(1:ind(1)-1); +% end; +% eval(['N=' tekstN ';'], 'N=16;') + + tekstO=get(hEditO,'UserData'); tekstO=tekstO(Ktory,:); + ind=find(tekstO==0); + if ~isempty(ind) + tekstO=tekstO(1:ind(1)-1); + end; +% eval(['O=' tekstO ';'], 'O=0;') + O=eval(tekstO, '0'); % \Fixed 2005.11.03 + O=round(O/100*M); % \Fixed 2005.11.03 nak³adkowanie podawane w procentach !!! + + + tekstW=get(hEditW,'UserData'); tekstW=tekstW(Ktory,:); + ind=find(tekstW==0); + if ~isempty(ind) + tekstW=tekstW(1:ind(1)-1); + end; + eval(['w=' tekstW ';'], 'w=ones(1,M);') + + w=w(:); + if length(w)<M; + w(M)=0; + else + w=w(1:M); + end; + + x=get(hp_re(Ktory), 'Ydata')+j*get(hp_im(Ktory), 'Ydata'); + +% O=floor(O/100*M); % \Fixed 2005.11.03 + if O>=M + O=M-1; + set(hEditO,'String', num2str(O/M*100)); + end; + N = fix((length(x)-O)/(M-O)); + set(hEditN, 'String', sprintf('%i', N)); + +% det_=get(h_det,'UserData'); det_=det_(Ktory,1); +% if det_==0, +% det='none'; +% else +% det_='linear'; +% end; + + [Spec, f, t]=specgram(x, K, 1, w, O); + Spec=(abs(Spec).^2)/norm(w)^2; +% [Per, f2]=psd(x, K, 1, w, O); + [Per, f2]=pwelch(x, w, O, K, 1); + Spec=abs(Spec); + + Re=get(h_real,'UserData'); + if ~Re(Ktory,1) + f=fftshift(f); + f(1:floor(K/2))=f(1:floor(K/2))-1; + f2=fftshift(f2); + f2(1:floor(K/2))=f2(1:floor(K/2))-1; + Spec=[Spec(ceil(K/2):K,:); Spec(1:floor(K/2),:)]; + Per=fftshift(Per); + end + + min_spec(Ktory)=min([min(Spec(isfinite(Spec))); 0]); + max_spec(Ktory)=max([max(Spec(isfinite(Spec))); 0.001]); + min_per(Ktory)=min([min(Per(isfinite(Per))); 0]); + max_per(Ktory)=max([max(Per(isfinite(Per))); 0.001]); + if get(h_dB, 'UserData') %dB + Spec=10*log10(Spec); + Per=10*log10(Per); + end + set(get(ha(2),'Ylabel'),'UserData', f); + set(get(ha(3),'Ylabel'),'UserData', Spec); + set(get(ha(4),'Ylabel'),'UserData', Per); + + %draw signal + axes(ha(2)); + if length(t)>1 + t2=t+(t(2)-t(1))/2; + else + t2=M/2; + end; + + if isnan(hp_spec_t(Ktory)) + hold on; +% hp_spec_t(Ktory)=plot(t2,max(Spec), 'Color', 'k'); + pomoc=abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata')); + hp_spec_t(Ktory)=plot(get(hp_re(Ktory),'Xdata'), pomoc, 'Color', 'k'); + if length(pomoc)>512 + set(hp_spec_t(Ktory), 'Marker', '.', 'MarkerSize', 4); + else + set(hp_spec_t(Ktory), 'LineStyle', '-'); + end; + hold off; + else +% set(hp_spec_t(Ktory),'Xdata', t2, 'Ydata', max(Spec), 'Color', 'k'); + set(hp_spec_t(Ktory),'Xdata', get(hp_re(Ktory),'Xdata'),... + 'Ydata', abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata')), 'Color', 'k'); + end + if length(t)==1, + set(ha(2), 'Xlim', [t(1)-0.5 t(1)+0.5], 'Ylim', [-1.1 1.1]*max(max_x)); + else + set(ha(2), 'Xlim', [t(1) t(length(t))+(t(2)-t(1))], 'Ylim', [-1.1 1.1]*max(max_x)); + end; +% set(get(ha(2),'ZLabel'),'UserData',[]); +% reset(get(ha(2),'ZLabel')); + eval('rmappdata(get(ha(2),''Zlabel''),''ZOOMAxesData'')','set(get(ha(2),''ZLabel''),''UserData'',[])'); + + %spektrogram + axes(ha(3)); + if isnan(hp_spec(Ktory)) + hold on; + hp_spec(Ktory)=image(t2, f, Spec); + colormap(hot); + hold off; + else + set(hp_spec(Ktory),'Xdata', t2, 'Ydata', f, 'Cdata', Spec); + end + if length(t)==1, + tlim_=[t(1)-0.5 t(1)+0.5]; + else + tlim_=[t(1) t(length(t))+t(2)-t(1)]; + end; + if all(Re) + set(ha(3), 'Ylim', [0 0.5], 'Xlim', tlim_); + else + set(ha(3), 'Ylim', [-0.5 0.5], 'Xlim', tlim_); + end +% set(get(ha(3),'ZLabel'),'UserData',[]); +% reset(get(ha(3),'ZLabel')); + eval('zoom reset', 'set(get(ha(3),''ZLabel''),''UserData'',[]);'); + + axes(ha(4)); + if isnan(hp_per(Ktory)) + hold on; + hp_per(Ktory)=plot(Per, f2, 'Color', 'k'); + hold off; + else + set(hp_per(Ktory),'Ydata', f2, 'Xdata', Per, 'Color', 'k'); + end + set(ha(4), 'Xdir', 'reverse', 'YTick', []); %, 'Xlim', [t(1) t(length(t))], 'Ylim', [-1.1 1.1]*max(max_x)); + if all(Re) + set(ha(4), 'Ylim', [0 0.5]); + else + set(ha(4), 'Ylim', [-0.5 0.5]); + end + eval('rmappdata(get(ha(4),''Zlabel''),''ZOOMAxesData'')','set(get(ha(4),''ZLabel''),''UserData'',[])'); + + set(hMenu,'UserData', [hp_re, hp_im, hp_spec_t, hp_spec_t2, hp_spec, hp_per, hp_per2, max_x, min_spec, max_spec, min_per, max_per]); + + % delete + if 1 + pom=get(hMenu,'UserData'); + hp_=pom(:,[4,7]); + hp_=hp_(isfinite(hp_)); + if length(hp_)>0 + delete(hp_) + pom(:,4)=NaN; + pom(:,7)=NaN; + set(hMenu,'UserData',pom); + end; + end + + SPECgraf('spec_ylim'); + SPECgraf zoom_on; + SPECgraf zoom_off; + return; + +elseif strcmp(Akcja, 'dB') + pom=get(h_dB, 'UserData'); + if pom~=get(h_dB, 'Value') + pom=get(hMenu,'UserData'); + hp_spec=pom(:,3); + for ind=1:length(hp_spec) + sygn=get(get(ha(3),'Ylabel'),'UserData'); + per=get(get(ha(4),'Ylabel'),'UserData'); + if get(h_dB, 'Value') %dB + sygn=10*log10(sygn); + per=10*log10(per); + else %lin + sygn=10.^(sygn/10); + per=10.^(per/10); + end; + set(get(ha(3),'Ylabel'),'UserData', sygn); + set(get(ha(4),'Ylabel'),'UserData', per); +% set(hp_spec(ind),'Cdata', sygn); + end; + set(h_dB, 'UserData', get(h_dB, 'Value')); + + hp_=pom(:,[4 7]); + hp_=hp_(isfinite(hp_)); + if length(hp_)>0 + delete(hp_) + pom(:,4)=NaN; + pom(:,7)=NaN; + set(hMenu,'UserData',pom); + end; + SPECgraf('spec_ylim'); + end + return + +elseif strcmp(Akcja, 'spec_ylim') + pom=get(hMenu,'UserData'); + hp_re=pom(:,1); + hp_im=pom(:,2); + hp_spec_t=pom(:,3); + hp_spec=pom(:,5); + hp_per=pom(:,6); + min_spec=pom(:,9); + max_spec=pom(:,10); + min_per=pom(:,11); + max_per=pom(:,12); + if get(h_dB, 'UserData') %dB + tekst=get(hEdit_dY,'String'); + eval(['dY=' tekst ';'], 'dY=120;'); + if dY<=0, dY=10; end; + params_=[min(min_spec) max(max_spec)]; + ind_params = find(abs(params_) <= eps); + if length(ind_params) > 0, + params_(ind_params) = NaN*ones(size(ind_params)); + end + ylim_=10*log10(params_); + if ~isfinite(ylim_(2)) + ylim_(2)=0; + end + ylim_(1)=ylim_(2)-dY; + params_=[min(min_per) max(max_per)]; + ind_params = find(abs(params_) <= eps); + if length(ind_params) > 0, + params_(ind_params) = NaN*ones(size(ind_params)); + end + ylim_per=10*log10(params_); + if ~isfinite(ylim_per(2)) + ylim_per(2)=0; + end + ylim_per(1)=ylim_per(2)-dY; + else + ylim_=[0 max(max_spec)]; + ylim_per=[0 max(max_per)]; + end + ylim_per(2)=max([ylim_per(2) ylim_(2)]); + f=get(get(ha(2),'Ylabel'),'UserData'); + Spec=get(get(ha(3),'Ylabel'),'UserData'); + Per=get(get(ha(4),'Ylabel'),'UserData'); + set(hp_spec_t(Ktory),'Ydata', abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata'))); + set(ha(2),'Ylim', ylim_+(ylim_(2)-ylim_(1))*[-0.1 0.1]); + Spec=64*(Spec-ylim_(1))/(ylim_(2)-ylim_(1)); + + set(hp_spec(Ktory),'Cdata', Spec); + set(hp_per(Ktory),'Xdata', Per, 'Ydata', f); + set(ha(4),'Xlim', ylim_per); + + if get(h_dB, 'UserData') %dB + set(hp_spec_t(Ktory),'Ydata', 20*log10(abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata')))); + else + set(hp_spec_t(Ktory),'Ydata', abs(get(hp_re(Ktory),'Ydata')+j*get(hp_im(Ktory),'Ydata'))); + end + + SPECgraf zoom_on; + eval('zoom reset', 'set(get(ha(3),''ZLabel''),''UserData'',[]);'); + SPECgraf zoom_off; + return +elseif strcmp(Akcja, 'zoom_on') + zoom on; +% pom=get(fig, 'WindowButtonDownFcn'); +% set(fig, 'WindowButtonDownFcn', 'SPECgraf zoom'); +% set(get(ha(3),'Xlabel'), 'UserData', pom); + return; +elseif strcmp(Akcja, 'zoom_off') + if get(findobj(fig,'tag','checkbox_zoom'),'Value') == 0, +% pom = get(get(ha(3),'Xlabel'), 'UserData'); +% set(fig, 'WindowButtonDownFcn', pom); + zoom off; + set(fig, 'WindowButtonDownFcn', 'SPECgraf zoom'); + set(get(ha(3),'Xlabel'), 'UserData', '1;'); + end + return; +elseif strcmp(Akcja, 'zoom_spec') + if get(findobj(fig,'tag','checkbox_zoom'),'Value') ~= 0, + Specgraf zoom_on; + else + Specgraf zoom_off; + end +elseif strcmp(Akcja, 'zoom') +% if strcmp(get(fig,'SelectionType'),'normal') | (gca~=ha(3)) + pause(0); + if (get(gco,'Parent')~=ha(3)) | get(findobj(fig,'tag','checkbox_zoom'),'Value') + eval(get(get(ha(3),'Xlabel'), 'UserData')); + elseif get(gco,'Parent')==ha(3) + pom=get(ha(3), 'CurrentPoint'); + f_=pom(1,2); t_=pom(1,1); + + pom_=get(hMenu,'UserData'); + hp_spec_t2=pom_(:,4); + hp_spec=pom_(:,5); + hp_per2=pom_(:,7); + f=get(hp_spec(Ktory), 'Ydata'); + ind_f=find(abs(f-f_)==min(abs(f-f_))); ind_f=ind_f(1); + t=get(hp_spec(Ktory), 'Xdata'); +% if length(t)>1, +% t=t+(t(2)-t(1))/2; +% end; + ind_t=find(abs(t-t_)==min(abs(t-t_))); + ind_t=ind_t(1); + set(findobj(fig,'tag', 'text_t_f'),... + 'ForegroundColor', 'r', 'String', sprintf('n=%i, f=%6.3f', t(ind_t),f(ind_f))); + + Spec=get(get(ha(3),'Ylabel'),'UserData'); + axes(ha(4)); + if length(Spec(:,ind_t))>length(f) + ind=find(f==0); + Spec(ind(1),:)=[]; + end; + if isnan(hp_per2(Ktory)) + hold on; + hp_per2(Ktory)=plot(Spec(:,ind_t),f, 'Color', 'r', 'LineWidth', 2); + hold off; + else + set(hp_per2(Ktory),'Xdata', Spec(:,ind_t), 'Ydata', f); + end +% pom=get(ha(4), 'Xlim'); +% pom(2)=max([pom(2) max(Spec(:,ind_t))]); +% set(ha(4),'Xlim', pom); + + axes(ha(2)); + if isnan(hp_spec_t2(Ktory)) + hold on; + hp_spec_t2(Ktory)=plot(t,Spec(ind_f,:), 'Color', 'r', 'LineWidth', 2); + hold off; + SPECgraf zoom_on; + SPECgraf zoom_off; + else + set(hp_spec_t2(Ktory),'Xdata', t, 'Ydata', Spec(ind_f,:)); + end + + pom_(Ktory,7)=hp_per2; + pom_(Ktory,4)=hp_spec_t2; + set(hMenu,'UserData',pom_); + end; + return; +end; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function fig_h=Specgraf_DrawFig +fig_h=figure; +set(fig_h, ... + 'Units', 'Normalized',... + 'Position', [0.1125 0.1188 0.7813 0.7448],... + 'Color', [1.0000 1.0000 1.0000],... + 'Name', 'Untitled',... + 'NumberTitle', 'off',... + 'Menu', 'none',... + 'Tag', 'figure1'... + ); +h=axes; +set(h, ... + 'Units', 'Normalized',... + 'Position', [0.0330 0.0881 0.2150 0.4867],... + 'Color', [1.0000 1.0000 1.0000],... + 'XColor', [0.0000 0.0000 0.0000],... + 'YColor', [0.0000 0.0000 0.0000],... + 'FontSize', 10,... + 'Box', 'on',... + 'Tag', 'per_axes'... + ); +h=axes; +set(h, ... + 'Units', 'Normalized',... + 'Position', [0.2900 0.6350 0.6990 0.1538],... + 'Color', [1.0000 1.0000 1.0000],... + 'XColor', [0.0000 0.0000 0.0000],... + 'YColor', [0.0000 0.0000 0.0000],... + 'FontSize', 10,... + 'Box', 'on',... + 'Tag', 'Signal_im_axes'... + ); +h=axes; +set(h, ... + 'Units', 'Normalized',... + 'Position', [0.2880 0.0867 0.7030 0.4867],... + 'Color', [1.0000 1.0000 1.0000],... + 'XColor', [0.0000 0.0000 0.0000],... + 'YColor', [0.0000 0.0000 0.0000],... + 'FontSize', 10,... + 'Box', 'on',... + 'Tag', 'spec_axes'... + ); +h=axes; +set(h, ... + 'Units', 'Normalized',... + 'Position', [0.2920 0.8266 0.6980 0.1580],... + 'Color', [1.0000 1.0000 1.0000],... + 'XColor', [0.0000 0.0000 0.0000],... + 'YColor', [0.0000 0.0000 0.0000],... + 'FontSize', 10,... + 'Box', 'on',... + 'Tag', 'Signal_re_axes'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'frame',... + 'Units', 'Normalized',... + 'Position', [0.0050 0.7972 0.2400 0.1930],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', '',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'frame2'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'frame',... + 'Units', 'Normalized',... + 'Position', [0.0050 0.5916 0.2400 0.2028],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', '',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'frame4'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.1190 0.6364 0.0280 0.0350],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', '[%]',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text23'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'checkbox',... + 'Units', 'Normalized',... + 'Position', [0.8720 0.0126 0.0660 0.0196],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'zoom',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'Specgraf zoom_spec',... + 'Tag', 'checkbox_zoom'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'pushbutton',... + 'Units', 'Normalized',... + 'Position', [0.0140 0.0098 0.0660 0.0378],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Exit',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf Exit',... + 'Tag', 'pushbutton5'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.4640 0.0028 0.3540 0.0350],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', '',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text_t_f'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.1750 0.0126 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec_ylim'')',... + 'Tag', 'dY_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.1110 0.0154 0.0620 0.0308],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'dY [dB] =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text21'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'checkbox',... + 'Units', 'Normalized',... + 'Position', [0.9270 0.5748 0.0500 0.0322],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'dB',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''dB'')',... + 'Tag', 'dB_checkbox'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'pushbutton',... + 'Units', 'Normalized',... + 'Position', [0.0660 0.4909 0.0600 0.0420],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Delete',... + 'Value', 0,... + 'Visible', 'off',... + 'Callback', 'SPECgraf(''delete'')',... + 'Tag', 'pushbutton4'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'pushbutton',... + 'Units', 'Normalized',... + 'Position', [0.0120 0.4909 0.0480 0.0420],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'New',... + 'Value', 0,... + 'Visible', 'off',... + 'Callback', 'SPECgraf(''new'')',... + 'Tag', 'pushbutton3'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.1580 0.6769 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'N_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.1280 0.6825 0.0300 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'N =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text18'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0390 0.8014 0.0720 0.0378],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''signal'')',... + 'Tag', 'L_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0090 0.8028 0.0290 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'L =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text17'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'checkbox',... + 'Units', 'Normalized',... + 'Position', [0.1290 0.7301 0.1100 0.0252],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'detrend',... + 'Value', 0,... + 'Visible', 'off',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'detrend_checkbox'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0400 0.6378 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'O_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0110 0.6378 0.0280 0.0294],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'O =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text16'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0520 0.6000 0.1870 0.0336],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'w_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0130 0.5986 0.0400 0.0294],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'w[n] =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text15'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.1670 0.8042 0.0720 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''signal'')',... + 'Tag', 'Noise_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.1190 0.8042 0.0470 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Noise=',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text14'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0410 0.6769 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'M_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0110 0.6825 0.0300 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'M =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text13'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.1340 0.4909 0.1030 0.0392],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'off',... + 'Callback', 'SPECgraf(''change_name'')',... + 'Tag', 'Name_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'popupmenu',... + 'Units', 'Normalized',... + 'Position', [0.0120 0.5413 0.2260 0.0294],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Popup Menu',... + 'Value', 1,... + 'Visible', 'off',... + 'Callback', 'SPECgraf(''Choose'')',... + 'Tag', 'choose_popupmenu'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'checkbox',... + 'Units', 'Normalized',... + 'Position', [0.1160 0.9580 0.1110 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'real signal',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''signal'')',... + 'Tag', 'real_checkbox'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0100 0.7622 0.1470 0.0266],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Spectrograf parameters',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text10'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0400 0.7259 0.0750 0.0364],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''spec'')',... + 'Tag', 'K_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0140 0.7329 0.0240 0.0252],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'K =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text9'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'edit',... + 'Units', 'Normalized',... + 'Position', [0.0390 0.8462 0.2010 0.1077],... + 'BackGroundColor', [1.0000 1.0000 1.0000],... + 'String', 'Edit Text',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', 'SPECgraf(''signal'')',... + 'Tag', 'x_edit'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0130 0.9245 0.0240 0.0252],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'x =',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text4'... + ); +h=uicontrol; +x=version; +if (x(1)>='5'), + set(h, ... + 'FontSize', 10); +end; +set(h, ... + 'Style', 'text',... + 'Units', 'Normalized',... + 'Position', [0.0120 0.9636 0.1010 0.0238],... + 'BackGroundColor', [0.9255 0.9137 0.8471],... + 'String', 'Testing signal',... + 'Value', 0,... + 'Visible', 'on',... + 'Callback', '',... + 'Tag', 'text2'... + ); diff --git a/Ex3/matlab/demo_decym_1stop.m b/Ex3/matlab/demo_decym_1stop.m new file mode 100644 index 0000000000000000000000000000000000000000..4e713a096dd856b00b0945e959178bd50a395204 --- /dev/null +++ b/Ex3/matlab/demo_decym_1stop.m @@ -0,0 +1,120 @@ +function demo_decym_1stop +% Decymacja jednostopniowa +close all; +clear all; + +%definiowanie wejœciowej i wyjœciowej szybkoœci próbkowania +fold = 10240; +fnew = 320; + +%obliczanie krotnoœci decymacji +M = fold/fnew; + +%obliczanie granic pasma przepustowego i pasma zaporowego +vp = 0.4/M; +vz = 0.5/M; +vg = 0.5/M; +vp1 = 0.4/M; +vz1 = 0.6/M; + +Ap = 0.2; +dp = -((1-10^(Ap/20))/(1+10^(Ap/20))); +As = 60; +ds = 10^(-As/20); + +%definiowanie sygna³u testowego +n = 0:5*fold-1; +x = sin(2*pi*9/fold*n)+1/4*sin((2*pi*27/fold*n)+pi/4)+1/16*sin((2*pi*36/fold*n)+pi/6)+sin(2*pi*49/fold*n); +x = x + randn(size(x))/100000; + +%Widmo sygna³u wejsciowego +figure(1) +plot(n,20*log10(abs(fft(x)))); +axis ([0 fold/2 -100 100]); + +%projektowanie filtru +[nn,fo,mo,w] = remezord( [vp vz], [1 0], [dp ds], 1); + +h = remez(nn,fo,mo,w); +[H, F2] = freqz(h, 1, 8192*32, 1); + +%Charakterystyka amplitudowa filtru H' +figure(2) +subplot(2,2,1); +plot(F2,20*log10(abs(H))); +hold on; +plot ([vp vp],[-80 5],'k--'); +plot ([vz vz],[-80 5],'k:'); +plot ([vg vg],[-80 5],'k-'); +axis ([0 0.5 -80 5]); +title('a'); + + +y = conv(h,x); + +p = length(h)-1; +yyy=y(p+1:M:end-1); + +wind = blackman(length(yyy)); +Y = 20*log10(abs(fft(wind'.*yyy,32768))); + +%Widmo sygnalu x[n] po filracji +subplot(2,2,2); +plot(Y); +title('b'); +axis ([0 length(Y)/2 -100 55]); + +%projektowanie filtru2 +[nn2,fo2,mo2,w2] = remezord( [vp1 vz1], [1 0], [dp ds], 1); + +h2 = remez(nn2,fo2,mo2,w2); +[H2, F22] = freqz(h2, 1, 8192*32, 1); + +%Charakterystyka amplitudowa filtru H2 +subplot(2,2,3); +plot(F22,20*log10(abs(H2))); +hold on; +plot ([vp1 vp1],[-80 5],'k--'); +plot ([vz1 vz1],[-80 5],'k:'); +plot ([vg vg],[-80 5],'k-'); +axis ([0 0.5 -80 5]); +title('c'); + +y2 = conv(h2,x); + +p2 = length(h2)-1; +yyy2=y2(p2+1:M:end-1); + +n22 = 0:fold-1; +wind2 = blackman(length(yyy2)); +Y2 = 20*log10(abs(fft(wind2'.*yyy2,32768))); + +%Widmo sygnalu x[n] po filtracji +subplot(2,2,4); +plot(Y2); +title('d'); +axis ([0 length(Y2)/2 -100 55]); + + + +K = 8192*32; % zeropadding +wind11 = blackman(length(yyy)); +Y11 = 20*log10(abs(fft(wind11'.*yyy,K))); +wind22 = blackman(length(yyy2)); +Y22 = 20*log10(abs(fft(wind22'.*yyy2,K))); + +%Widmo sygnalu x[n] po decymacji +figure(3) +subplot(2,1,1); + +plot(Y11); +title('a'); +axis ([0 length(Y11)/2 -100 50]); +subplot(2,1,2); +plot(Y22); +title('b'); +axis ([0 length(Y22)/2 -100 50]); + +for i=1:3, + set(i, 'color', 'w'); +end diff --git a/Ex3/matlab/demo_inter_1stop.m b/Ex3/matlab/demo_inter_1stop.m new file mode 100644 index 0000000000000000000000000000000000000000..78312a2a7efe0f2e38c9ffb032402e6c97ef17d7 --- /dev/null +++ b/Ex3/matlab/demo_inter_1stop.m @@ -0,0 +1,127 @@ +function demo_inter_1stop +close all; +clear all; + +%definiowanie wejœciowej i wyjœciowej szybkoœci próbkowania +fold = 100; +fnew = 400; + +%obliczanie krotnoœci interpolacji +L = fnew/fold; + +%obliczanie granic pasma przepustowego i pasma zaporowego +vp = 0.4/L; +vz = 0.5/L; +vg = 0.5/L; +vp1 = 0.4/L; +vz1 = 0.6/L; + +Ap = 0.2; +dp = -((1-10^(Ap/20))/(1+10^(Ap/20))); +As = 60; +ds = 10^(-As/20); + +%definiowanie sygna³u testowego +n = 0:5*fold-1; +x = sin(2*pi*9/fold*n)+1/4*sin((2*pi*27/fold*n)+pi/4)+1/16*sin((2*pi*36/fold*n)+pi/6)+sin(2*pi*49/fold*n); +x = x + randn(size(x))/100000; + +figure(1) +subplot(1,2,1); +plot(n,20*log10(abs(fft(x)))); +title('a'); +axis ([0 length(x)/2 -100 50]); + +%uzupe³nianie zerami +xx = zeros(1,L*length(x)); +xx(1:L:length(x)*L)=x; + +n2 = 0:fnew-1; + + +subplot(1,2,2); +plot(n2,20*log10(abs(fft(xx(1:L*fold))))); +title('b'); +axis ([0 length(x)/2 -100 50]); + +%projektowanie filtru +[nn,fo,mo,w] = remezord( [vp vz], [1 0], [dp ds], 1); +h = L*remez(nn,fo,mo,w); +[H, F2] = freqz(h/L, 1, 8192*32, 1); + + +figure(2) +subplot(2,2,1); +plot(F2,20*log10(abs(H))); +hold on; +plot ([vp vp],[-80 5],'k--'); +plot ([vz vz],[-80 5],'k:'); +plot ([vg vg],[-80 5],'k-'); +axis ([0 0.5 -80 5]); +title('a'); + + +y = conv(h,xx); + +p = length(h)-1; +yy=y(p+1:1:end); + + + +wind = blackman(length(yy)); +Y = 20*log10(abs(fft(wind'.*yy,32768))); + +subplot(2,2,2); +plot(Y); +axis ([0 length(Y)/2 -155 50]); +title('b'); + +%projektowanie filtru2 +[nn2,fo2,mo2,w2] = remezord( [vp1 vz1], [1 0], [dp ds], 1); +h2 = L*remez(nn2,fo2,mo2,w2); +[H2, F22] = freqz(h2/L, 1, 8192*32, 1); + +subplot(2,2,3); +plot(F22,20*log10(abs(H2))); +hold on; +plot ([vp1 vp1],[-80 5],'k--'); +plot ([vz1 vz1],[-80 5],'k:'); +plot ([vg vg],[-80 5],'k-'); +axis ([0 0.5 -80 5]); +title('c'); + + +y2 = conv(h2,xx); + +p2 = length(h2)-1; +yy2=y2(p2+1:1:end); + + +wind2 = blackman(length(yy2)); +Y2 = 20*log10(abs(fft(wind2'.*yy2,32768))); + +subplot(2,2,4); +plot(Y2); +%plot(20*log10(abs(fft(yy2)))); +axis ([0 length(Y2)/2 -155 50]); +title('d'); + + +figure(3); +K = 8192*32; % zeropadding +okno = chebwin(length(yy), 150).'; + +YY= 20*log10(abs(fft(yy.*okno, K))); +plot(YY); + +hold on +okno = chebwin(length(yy2), 150).'; + +plot(20*log10(abs(fft(yy2.*okno, K))), 'r'); +axis ([0 length(YY) -100 50]); +hold off + +for i=1:3, + set(i, 'color', 'w'); +end + diff --git a/Ex3/matlab/demo_inter_2stop.m b/Ex3/matlab/demo_inter_2stop.m new file mode 100644 index 0000000000000000000000000000000000000000..f396afe7ae1165c1e02c697b3d70c56ba20b8d53 --- /dev/null +++ b/Ex3/matlab/demo_inter_2stop.m @@ -0,0 +1,142 @@ +function demo_inter_2stop +close all; +clear all; + +%definiowanie wejœciowej i wyjœciowej szybkoœci próbkowania +fold = 320; +fnew = 10240; +Fg = 128; + +%obliczanie krotnoœci interpolacji +L = fnew/fold; + +% implementacja jednostopniowa +vp = Fg/fnew +vz = (fold/2)/fnew + +Ap = 0.1; +dp = -((1-10^(Ap/20))/(1+10^(Ap/20))); +As = 60; +ds = 10^(-As/20); + +%projektowanie filtru +[nn,fo,mo,w] = remezord( [vp vz], [1 0], [dp ds], 1); +h = L*remez(nn,fo,mo,w); +[H, F] = freqz(h/L, 1, 8192*32, fnew); + +figure(1) +subplot(2,1,1); +plot(F,20*log10(abs(H))); +hold on; +plot ([vp vp]*fnew,[-80 5],'k--'); +plot ([vz vz]*fnew,[-80 5],'k:'); +hold off; +axis ([0 0.5*fnew -80 5]); + +N = length(h) + + +L1 = 8; +%obliczanie granic pasma przepustowego i pasma zaporowego +% filtr w pierwszym stopniu pracuje z szybkoœci¹ L1*fold) +vp = Fg/(L1*fold) +vz = (fold/2)/(L1*fold) +% % vz = 0.5/L; +% vg = 0.5/L; +% vp1 = 0.4/L; +% vz1 = 0.6/L; + +Ap = 0.05; +dp = -((1-10^(Ap/20))/(1+10^(Ap/20))); +As = 60; +ds = 10^(-As/20); + + +%projektowanie filtru +[nn,fo,mo,w] = remezord( [vp vz], [1 0], [dp ds], 1); +h1 = L1*remez(nn,fo,mo,w); +[H1, F2] = freqz(h1/L1, 1, 8192*32, 1); + +N1 = length(h1) + +figure(2) +subplot(2,2,1); +plot(F2,20*log10(abs(H1))); +hold on; +plot ([vp vp],[-80 5],'k--'); +plot ([vz vz],[-80 5],'k:'); +hold off; +axis ([0 0.5 -80 5]); +title('a'); + +subplot(2,2,2); +plot(F2,20*log10(abs(H1))); +hold on; +plot ([vp vp],[-80 5],'k--'); +plot ([vz vz],[-80 5],'k:'); +hold off; +axis ([0 vz -Ap Ap]); +title('b'); + + +% drugi stopieñ interpolacji +L2 = 4; +% filtr pracuje z szybkoœci¹ fnew +vp1 = Fg/fnew; +vz1 = (L1*fold-Fg)/fnew + +%projektowanie filtru2 +[nn2,fo2,mo2,w2] = remezord( [vp1 vz1], [1 0], [dp ds], 1); +h2 = L2*remez(nn2,fo2,mo2,w2); +[H2, F22] = freqz(h2/L2, 1, 8192*32, 1); + +subplot(2,2,3); +plot(F22,20*log10(abs(H2))); +hold on; +plot ([vp1 vp1],[-80 5],'k--'); +plot ([vz1 vz1],[-80 5],'k:'); +% plot ([vg vg],[-80 5],'k-'); +hold off; +axis ([0 0.5 -80 5]); +title('c'); + + +subplot(2,2,4); +plot(F2,20*log10(abs(H2))); +hold on; +plot ([vp1 vp1],[-80 5],'k--'); +plot ([vz1 vz1],[-80 5],'k:'); +hold off; +axis ([0 vz/L2 -Ap Ap]); +title('d'); + + +N2 = length(h2) + + +h1_L2 = zeros(N1*L2-(L2-1), 1); +h1_L2(1:L2:end) = h1; +[H1_L2, F1_L2] = freqz(h1_L2/L1, 1, 8192*32, 1); + +h_all = conv(h1_L2, h2); +N_all = length(h_all) + +figure(3) +subplot(2,1,1) +plot(F1_L2,20*log10(abs(H1_L2))); +hold on; +plot(F2,20*log10(abs(H2)), 'r'); +hold off +axis ([0 0.5 -80 5]); +title('charakterystyki filtrów sk³adowych przeniesionych na szybkoœæ próbkowania fnew'); + +subplot(2,1,2) +plot(F1_L2,20*log10(abs(H1_L2.*H2))); + +axis ([0 0.5 -80 5]); +title('charakterystyka zbiorcza'); + +figure(1) +subplot(2,1,2) +plot(F1_L2*fnew,20*log10(abs(H1_L2.*H2))); +axis ([0 0.5*fnew -80 5]); diff --git a/Ex3/matlab/design_task_3.m b/Ex3/matlab/design_task_3.m new file mode 100644 index 0000000000000000000000000000000000000000..7fc6a4d85db5f94fe3f0bfabe700407a6f2bafec --- /dev/null +++ b/Ex3/matlab/design_task_3.m @@ -0,0 +1,98 @@ +function h=design_task_3 +% type = 2; +% +% %interpolation filter +% switch type, +% case 1, +% Fp1 = 22050; Fp2 = 44100; +% +% case 2, +% Fp1 = 8000; Fp2 = 32000; +% F_trans = [3000 5000]; +% end +% L = Fp2 / Fp1; + +Fsymb = 2400; Fp_out = 48000; + +L = Fp_out/Fsymb + +L1 = 4 +L2 = L / L1 + +% filtr dla pierwszego stopnia interpolacji +r = 0.33; +h_rc=rcos4(20*L1,L1, 0.33); + +K = 8192; +[H_rc, f] = freqz(h_rc/L1, 1, K, L1*Fsymb); + +figure(1) +subplot(3,1,1) +plot(h_rc) +subplot(3,1,2) +plot(f, abs(H_rc)) +set(gca, 'Ylim', [0, 1.1], 'Xlim', [0, L1*Fsymb/2]) +subplot(3,1,3) +plot(f, 20*log10(abs(H_rc))) +set(gca, 'Ylim', [-70, 3], 'Xlim', [0, L1*Fsymb/2]) + +% filtr dla drugiego stopnia interpolacji +Fd = Fsymb/2 * (1+0.33); +% !!! pasmo przepustowe filtru drugiego stopnia obejmuj�ce +% pasmo przepustowe i przej�ciowe filtru pierwszego stopnia +% !!! jest to nietypowe rozwi�zanie gwarantuj�ce zachowanie charakteru +% pasma przej�ciowego filtru kszta�tuj�cego +Fg = L1*Fsymb - Fd; + +% zafalowanie w pasmie +/-0.1 dB, t�umienie poza pasmem -60dB +dp = 10.^(0.1/20)-1; +ds = 10.^(-60/20); + +c = firpmord( [Fd, Fg], [1 0], [dp ds], Fp_out, 'cell'); +h2 = firpm(c{:}); +N2 = length(h2) +[H2, f] = freqz(h2, 1, K, Fp_out); + +figure(2) +subplot(3,1,1) +plot(h2) +subplot(3,1,2) +plot(f, abs(H2)) +set(gca, 'Ylim', [0, 1.1], 'Xlim', [0, Fp_out/2]) +subplot(3,1,3) +plot(f, 20*log10(abs(H2))) +set(gca, 'Ylim', [-70, 3], 'Xlim', [0, Fp_out/2]) + +% analiza filtru zbiorczego +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 +% filtr h_rc - pracuje na L1*Fsymb +% przenosimy go na szybko�� pr�bkowania filtru drugiego +h1 = zeros(1, length(h_rc)*L2); +h1(1:L2:end) = h_rc; +[H1, f] = freqz(h1/L1, 1, K, Fp_out); + +figure(3) +subplot(2,1,1) +plot(f, abs(H1), 'r'); +hold on +plot(f, abs(H2), 'b'); +plot(f, abs(H1.*H2), 'k'); +hold off +set(gca, 'Ylim', [0, 1.1], 'Xlim', [0, Fp_out/2]) +subplot(2,1,2) +plot(f, 20*log10(abs(H1)), 'r'); +hold on +plot(f, 20*log10(abs(H2)), 'b'); +plot(f, 20*log10(abs(H1.*H2)), 'k'); % filtr zbiorczy +hold off +set(gca, 'Ylim', [-80, 3], 'Xlim', [0, Fp_out/2]) + +dane.h = h_rc; +dane.Fp = L1*Fsymb; +save_filter_coef('cw3_zad3_h_rc', dane, 1); + + +dane.h = L2*h2; +dane.Fp = Fp_out; +save_filter_coef('cw3_zad3_h2', dane, 1); + diff --git a/Ex3/matlab/ex3_task3_h2.coef b/Ex3/matlab/ex3_task3_h2.coef new file mode 100644 index 0000000000000000000000000000000000000000..0c6aaa170094652f5606392044dbb86ea4cc4eb0 Binary files /dev/null and b/Ex3/matlab/ex3_task3_h2.coef differ diff --git a/Ex3/matlab/ex3_task3_h_rc.coef b/Ex3/matlab/ex3_task3_h_rc.coef new file mode 100644 index 0000000000000000000000000000000000000000..343e7804ae779229df307dab2e9db5b986d0573b Binary files /dev/null and b/Ex3/matlab/ex3_task3_h_rc.coef differ diff --git a/Ex3/matlab/gen_signal.m b/Ex3/matlab/gen_signal.m new file mode 100644 index 0000000000000000000000000000000000000000..d28a97a4be5139744c678f2ba6a9230021882698 --- /dev/null +++ b/Ex3/matlab/gen_signal.m @@ -0,0 +1,26 @@ +function x = gen_signal(nr_sygnalu, fold, L, M) + +N = 5*fold; +while (N < 1024) | (N*L/M < 1024), + N = N*2; +end + +n = 0:N-1; +switch nr_sygnalu + case 1, + x = sin(2*pi*9/fold*n)+1/4*sin((2*pi*27/fold*n)+pi/4)+1/16*sin((2*pi*36/fold*n)+pi/6)+sin(2*pi*49/fold*n); + x = x + randn(size(x))/100000; + case 2, + s = 6; + x = 0; + while s < fold + a = randn; + x = x + a*sin(2*pi*s/fold*n); + s = s + 6; + end + x = x + randn(size(x))/100000; + case 3, + % x = + case 4, + % x = +end diff --git a/Ex3/matlab/guihelp.m b/Ex3/matlab/guihelp.m new file mode 100644 index 0000000000000000000000000000000000000000..9d9f8151d5e6513cb75fbdd6415b1fe4c75d73d3 --- /dev/null +++ b/Ex3/matlab/guihelp.m @@ -0,0 +1,37 @@ +function guihelp + +screen_resolution = get(0, 'ScreenSize'); +screen_width = screen_resolution(3); +screen_height = screen_resolution(4); + +window_width = 427; +window_height = 525; + +window_position = [(screen_width/2 - window_width/2),... + (screen_height/2 - window_height/2),... + window_width,... + window_height]; + +main = figure('Name','HELP',... + 'NumberTitle','off',... + 'Resize','off',... + 'Visible','on',... + 'MenuBar', 'none',... + 'DoubleBuffer', 'on',... + 'units', 'pixels',... + 'color', [.9 .9 .9],... + 'Position', window_position); + +panel1 = uipanel('Parent', main, 'Units', 'pixels', 'Visible', 'on', 'Position', [5 5 420 515]); + +pomoc = sprintf(['Interface aplikacji zostal podzielony na trzy sekcje.\n\n'... + 'I sekcja:\nWybor sygnalu testowego, definiowanie wejsciowej i wyjsciowej szybkosci probkownaia.\nSkrypt wylicza krotnosci L i M oraz czêstotliwoœæ, do której s¹ przenoszone sk³adowe sygna³u wejœciowego (Fmax).\n'... + ' UWAGA! Czêstotliwoœæ Fmax wyznacza pocz¹tek pasma zaporowego filtru interpolacyjnego dla realizacji jednostopniowej\n\n'... + 'II sekcja:\nDefiniowanie liczby stopni oraz krotnosci poszczegolnych stopni\n'... + ' UWAGA! Iloczyn wszystkich Li(Mi) musi byæ równy L(M)\nDolna i gorna granice pasma przejsciowego moze definiowac uzytkownik lub skorzystac z wyliczenia wartosci przez skrypt, ktore nastepnie moze edytowac.\n\n'... + 'III sekcja:\nPrzycisk uruchomienia zmiany szybkosci probkowania.\nWynikiem dzialania skryptu jest wyswietlenie liczby wspolczynnikow dla filtrow kazdego ze stopni oraz wykresow.\n'... + ' UWAGA! Wyœwietlana wartoœæ czêstotliwoœci Fmax jest wyró¿niana na czerwono je¿eli dla danej implementacji wielostopniowej jest ona mniejsza wartoœci mo¿liwej do uzyskania w implementacji jednostopniowej (wartoœæ wyœwietlana w sekcji I).']); + +uicontrol('Parent', panel1, 'Style', 'text', 'String', pomoc, 'Position', [10 10 395 490], 'FontName', 'Times New Roman CE', 'FontSize', 10, 'HorizontalAlignment', 'left'); + +end \ No newline at end of file diff --git a/Ex3/matlab/id_1.m b/Ex3/matlab/id_1.m new file mode 100644 index 0000000000000000000000000000000000000000..7d51477d30853f59257dda2d643f473af6d4ba80 --- /dev/null +++ b/Ex3/matlab/id_1.m @@ -0,0 +1,109 @@ +function N = id_1(nr_sygnalu, fold, fnew, Li, Mi, FPi, FSi) + +L = fnew / gcd(fold, fnew); +M = fold / gcd(fold, fnew); + +L1 = Li(1); +M1 = Mi(1); + +fp1 = FPi(1); +fs1 = FSi(1); + + +% %definiowanie wejœciowej i wyjœciowej szybkoœci próbkowania +% fold = 320; +% fnew = 10240; +% +% %obliczanie krotnoœci +% L = fnew/gcd(fold,fnew); +% M = fold/gcd(fold,fnew); +% L1 = L; +% M1 = M; + +%obliczanie granic pasma przepustowego i pasma zaporowego +% fg1 = min(0.5/L,0.5/M); + +%definiowanie sygna³u testowego +x = gen_signal(nr_sygnalu, fold, L, M); + +%obliczanie zafalowan w pasmach przepustowym i zaporowym +Ap = 0.1; +dp = -((1-10^(Ap/20))/(1+10^(Ap/20))); +As = 60; +ds = 10^(-As/20); + +%uzupe³nianie zerami(interpolacja – wstawiamy L1-1 zer pomiedzy ka¿d¹ parê próbek) +xx = zeros(1,L1*length(x)); +xx(1:L1:length(x)*L1)=x; + +%projektowanie filtru +[nn,fo,mo,w] = firpmord( [fp1 fs1], [1 0], [dp ds], 1); +if nn < 3, nn=3; end; + +if nn > 1000, + N = nn; + disp('wymagany rz¹d filtru > 1000') + return +end +tic +h1 = L1*firpm(nn,fo,mo,w); +toc +[H, F2] = freqz(h1/L1, 1, 8192*32, fold*L); + + +%splot sygna³u po interpolacji z odpowiedzi¹ impulsow¹ filtru +y = conv(h1,xx); + +% usuwanie stanu przejsciowego i decymacja sygba³u - wybieramy co M-ta +% probke +p = length(h1)-1; +y11 = y(p+1:M1:end); + + + +%wykresy + +%widmo sygna³u wejœciowego +wind0 = blackman(length(x)); +Y0 = 20*log10(abs(fftshift(fft(wind0'.*x,32768)))); +F_Y0 = linspace(-fold/2, fold/2, 32768+1); F_Y0(end) = []; +figure(2) +subplot(1,2,1); +plot(F_Y0, Y0); +set(gca, 'xlim', [-fold/2, fold/2]); +xlabel('F [Hz]'); +title('syg. wejsciowy'); + +%widmo sygba³u wyjsciowego +figure(2) +subplot(1,2,2); +wind1 = blackman(length(y11)); +Y1 = 20*log10(abs(fftshift(fft(wind1'.*y11,32768)))); +F_Y1 = linspace(-fnew/2, fnew/2, 32768+1); F_Y1(end) = []; +plot(F_Y1, Y1); +set(gca, 'xlim', [-fnew/2, fnew/2]); +xlabel('F [Hz]'); +title('syg. wyjsciowy'); + + + +%charakterystyka amplitudowa filtru 1 +figure(3) +plot(F2,20*log10(abs(H))); +hold on; +plot ([fp1 fp1]*fold*L,[-80 5],'k--'); +plot ([fs1 fs1]*fold*L,[-80 5],'k:'); +% plot ([fg1 fg1],[-80 5],'k-'); +axis ([0 fold*L/2 -80 5]); +xlabel('F [Hz]'); +title('filtr 1'); + +for i=2:3, + set(i, 'color', 'w'); +end + + + +N = nn+1; + +end \ No newline at end of file diff --git a/Ex3/matlab/id_2.m b/Ex3/matlab/id_2.m new file mode 100644 index 0000000000000000000000000000000000000000..5794f0b526c5efb7885c6d3af888e7fa315be26c --- /dev/null +++ b/Ex3/matlab/id_2.m @@ -0,0 +1,171 @@ +function N = id_2(nr_sygnalu, fold, fnew, Li, Mi, FPi, FSi) + +L = fnew / gcd(fold, fnew); +M = fold / gcd(fold, fnew); + +L1 = Li(1); +M1 = Mi(1); +L2 = Li(2); +M2 = Mi(2); + +fp1 = FPi(1); +fs1 = FSi(1); +fp2 = FPi(2); +fs2 = FSi(2); + + + +% %definiowanie wejœciowej i wyjœciowej szybkoœci próbkowania +% fold = 320; +% fnew = 10240; +% +% %obliczanie krotnoœci +% L = fnew/gcd(fold,fnew); +% M = fold/gcd(fold,fnew); +% L1 = 32; +% L2 = L/L1; +% M1 = 1; +% M2 = M/M1; + + +%definiowanie sygna³u testowego +x = gen_signal(nr_sygnalu, fold, L, M); + +%obliczanie zafalowan w pasmach przepustowym i zaporowym +Ap = 0.1; +dp = -((1-10^(Ap/20))/(1+10^(Ap/20))); +As = 60; +ds = 10^(-As/20); + +%uzupe³nianie zerami I stopien (interpolacja – wstawiamy L1-1 zer pomiedzy ka¿d¹ parê próbek) +xx = zeros(1,L1*length(x)); +xx(1:L1:length(x)*L1)=x; + +[nn1,fo1,mo1,w1] = remezord( [fp1 fs1], [1 0], [dp/2 ds], 1); +if nn1 < 3, nn1=3; end; +[nn,fo,mo,w] = remezord( [fp2 fs2], [1 0], [dp/2 ds], 1); +if nn < 3, nn=3; end; +N = [ nn1, nn ]; +if sum(N) > 1000, + disp('wymagany sumaryczny rz¹d filtrów > 1000') + return +end + + +%projektowanie filtru + +h1 = L1*remez(nn1,fo1,mo1,w1); +% [H1, F21] = freqz(h1/L1, 1, 8192*32, 1); +[H1, F21] = freqz(h1/L1, 1, 8192*32, fold*L1); + +%splot sygna³u po interpolacji z odpowiedzi¹ impulsow¹ filtru stopien I +y = conv(h1,xx); + +% usuwanie stanu przejsciowego i decymacja sygba³u - wybieramy co M1-ta +% probke +p = length(h1)-1; +yy=y(p+1:M1:end); + +%uzupe³nianie zerami stopien II +xx2 = zeros(1,L2*L1*length(x)/M1); +xx2(1:L2:length(x)*L2*L1/M1)=yy; + +%projektowanie filtru stopien II +h2 = L2*remez(nn,fo,mo,w); +[H2, F2] = freqz(h2/L2, 1, 8192*32, fold*L1/M1*L2); + +%splot sygna³u po interpolacji z odpowiedzi¹ impulsow¹ filtru stopien II +y2 = conv(h2,xx2); + +% usuwanie stanu przejsciowego i decymacja sygna³u - wybieramy co M2-ta +% probke +p2 = length(h2)-1; +yy2=y2(p2+1:M2:end); + +%wykresy +% figure(12) +% subplot(1,2,1); +% plot(x); +% subplot(1,2,2); +% plot(yy2); + +%widmo sygna³u wejœciowego +wind0 = blackman(length(x)); +Y0 = 20*log10(abs(fftshift(fft(wind0'.*x,32768)))); +F_Y0 = linspace(-fold/2, fold/2, 32768+1); F_Y0(end) = []; +figure(2) +subplot(1,2,1); +plot(F_Y0, Y0); +set(gca, 'xlim', [-fold/2, fold/2]); +xlabel('F [Hz]'); +title('syg. wejsciowy'); + +%widmo sygba³u wyjsciowego +figure(2) +subplot(1,2,2); +wind1 = blackman(length(yy2)); +Y1 = 20*log10(abs(fftshift(fft(wind1'.*yy2,32768)))); +F_Y1 = linspace(-fnew/2, fnew/2, 32768+1); F_Y1(end) = []; +plot(F_Y1, Y1); +set(gca, 'xlim', [-fnew/2, fnew/2]); +xlabel('F [Hz]'); +title('syg. wyjsciowy'); + +%filtr I +figure(3) +plot(F21,20*log10(abs(H1))); +hold on; +plot ([fp1 fp1]*fold*L1,[-80 5],'k--'); +plot ([fs1 fs1]*fold*L1,[-80 5],'k:'); +% plot ([fg1 fg1]*fold*L1,[-80 5],'k-'); +axis ([0 0.5*fold*L1 -80 5]); +xlabel('F [Hz]'); +title('filtr I'); + +%filtr II +figure(4) +plot(F2,20*log10(abs(H2))); +hold on; +plot ([fp2 fp2]*fold*L1/M1*L2,[-80 5],'k--'); +plot ([fs2 fs2]*fold*L1/M1*L2,[-80 5],'k:'); +% plot ([fg2 fg2]*fold*L1/M1*L2,[-80 5],'k-'); +axis ([0 0.5*fold*L1/M1*L2 -80 5]); +xlabel('F [Hz]'); +title('filtr II'); + +%Filtr zbiorczy +h2L = zeros(1,length(h2)*M1); +h2L(1:M1:length(h2)*M1)= h2; + +h1L = zeros(1,length(h1)*L2); +h1L(1:L2:length(h1)*L2)= h1; + +t=conv(h1L,h2L); + +figure(5) +[H2L] = freqz(h2L/L2, 1, 8192*32, fold*L); +[H1L] = freqz(h1L/L1, 1, 8192*32, fold*L); +[H12, F212] = freqz(t/L, 1, 8192*32, fold*L); +subplot(2,1,1); +plot(F212,20*log10(abs(H1L))); +hold on +plot(F212,20*log10(abs(H2L)), 'r'); +hold off +axis ([0 0.5*fold*L -80 5]); +xlabel('F [Hz]'); +title('charakterystyki filtrów sk³adowych po przeniesieniu ich na szybkoœæ Fp1'); +subplot(2,1,2); +plot(F212,20*log10(abs(H12))); +axis ([0 0.5*fold*L -80 5]); +xlabel('F [Hz]'); +title('charakterystyka zbiorcza'); + +for i=2:5, + set(i, 'color', 'w'); +end + + + +N = [ nn1+1, nn+1 ]; + +end \ No newline at end of file diff --git a/Ex3/matlab/id_3.m b/Ex3/matlab/id_3.m new file mode 100644 index 0000000000000000000000000000000000000000..1a3a3409662e75afb616056d007a0fb5ddfae0b0 --- /dev/null +++ b/Ex3/matlab/id_3.m @@ -0,0 +1,214 @@ +function N = id_3(nr_sygnalu, fold, fnew, Li, Mi, FPi, FSi) + +L = fnew / gcd(fold, fnew); +M = fold / gcd(fold, fnew); + +L1 = Li(1); +M1 = Mi(1); +L2 = Li(2); +M2 = Mi(2); +L3 = Li(3); +M3 = Mi(3); + +fp1 = FPi(1); +fs1 = FSi(1); +fp2 = FPi(2); +fs2 = FSi(2); +fp3 = FPi(3); +fs3 = FSi(3); + + + +% %definiowanie wejœciowej i wyjœciowej szybkoœci próbkowania +% fold = 44100; +% fnew = 48000; +% +% %obliczanie krotnoœci +% L = fnew/gcd(fold,fnew) +% M = fold/gcd(fold,fnew) +% L1 = 8 +% L2 = 5 +% L3 = 4 +% M1 = 7 +% M2 = 7 +% M3 = 3 + + +%obliczanie granic pasma przepustowego i pasma zaporowego +% fg1 = (min(0.5/L,0.5/M)*fnew)/(fold*L1); +% fg2 = (min(0.5/L,0.5/M)*fnew)/(fold*L1*L2/M1); +% fg3 = (min(0.5/L,0.5/M)*fnew)/(fold*L1*L2*L3/(M1*M2)); + + +%definiowanie sygna³u testowego +x = gen_signal(nr_sygnalu, fold, L, M); + +%obliczanie zafalowan w pasmach przepustowym i zaporowym +Ap = 0.1; +dp = -((1-10^(Ap/20))/(1+10^(Ap/20))); +As = 60; +ds = 10^(-As/20); + + +%uzupe³nianie zerami I stopien (interpolacja – wstawiamy L1-1 zer pomiedzy ka¿d¹ parê próbek) +xx = zeros(1,L1*length(x)); +xx(1:L1:length(x)*L1)=x; + +[nn1,fo1,mo1,w1] = remezord( [fp1 fs1], [1 0], [dp/3 ds], 1); +if nn1 < 3, nn1=3; end; +[nn,fo,mo,w] = remezord( [fp2 fs2], [1 0], [dp/3 ds], 1); +if nn < 3, nn=3; end; +[nn3,fo3,mo3,w3] = remezord( [fp3 fs3], [1 0], [dp/3 ds], 1); +if nn3 < 3, nn3=3; end; + +N = [ nn1+1, nn+1, nn3+1 ]; +if sum(N) > 1000, + disp('wymagany sumaryczny rz¹d filtrów > 100') + return +end + +%projektowanie filtru +h1 = L1*remez(nn1,fo1,mo1,w1); +[H1, F21] = freqz(h1/L1, 1, 8192*32, fold*L1); + +%splot sygna³u po interpolacji z odpowiedzi¹ impulsow¹ filtru stopien I +y = conv(h1,xx); + +% usuwanie stanu przejsciowego i decymacja sygba³u - wybieramy co M1-ta +% probke +p = length(h1)-1; +yy=y(p+1:M1:end); + +%uzupe³nianie zerami stopien II +xx2 = zeros(1,L2*L1*length(x)/M1); +xx2(1:L2:length(x)*L2*L1/M1)=yy; + +%projektowanie filtru stopien II +h2 = L2*remez(nn,fo,mo,w); +[H2, F2] = freqz(h2/L2, 1, 8192*32, fold*L1/M1*L2); + +%splot sygna³u po interpolacji z odpowiedzi¹ impulsow¹ filtru stopien II +y2 = conv(h2,xx2); + +% usuwanie stanu przejsciowego i decymacja sygba³u - wybieramy co M2-ta +% probke +p2 = length(h2)-1; +yy2=y2(p2+1:M2:end); + +%uzupe³nianie zerami stopien III +xx3 = zeros(1,L3*(L2/M2)*(L1/M1)*length(x)); +xx3(1:L3:length(x)*(L1/M1)*(L2/M2)*L3)=yy2; + +%projektowanie filtru +h3 = L3*remez(nn3,fo3,mo3,w3); +[H3, F33] = freqz(h3/L3, 1, 8192*32, fold*L1/M1*L2/M2*L3); + +%splot sygna³u po interpolacji z odpowiedzi¹ impulsow¹ filtru stopien III +y3 = conv(h3,xx3); + +% usuwanie stanu przejsciowego i decymacja sygba³u - wybieramy co M3-ta +% probke +p3 = length(h3)-1; +yy3=y3(p3+1:M3:end); + + +%wykresy +%widmo sygna³u wejœciowego +wind0 = blackman(length(x)); +Y0 = 20*log10(abs(fftshift(fft(wind0'.*x,32768)))); +F_Y0 = linspace(-fold/2, fold/2, 32768+1); F_Y0(end) = []; +figure(2) +subplot(1,2,1); +plot(F_Y0, Y0); +set(gca, 'xlim', [-fold/2, fold/2]); +xlabel('F [Hz]'); +title('syg. wejsciowy'); + +%widmo sygba³u wyjsciowego +figure(2) +subplot(1,2,2); +wind1 = blackman(length(yy3)); +Y1 = 20*log10(abs(fftshift(fft(wind1'.*yy3,32768)))); +F_Y1 = linspace(-fnew/2, fnew/2, 32768+1); F_Y1(end) = []; +plot(F_Y1, Y1); +set(gca, 'xlim', [-fnew/2, fnew/2]); +xlabel('F [Hz]'); +title('syg. wyjsciowy'); + +%filtr I +figure(3) +plot(F21,20*log10(abs(H1))); +hold on; +plot ([fp1 fp1]*fold*L1,[-80 5],'k--'); +plot ([fs1 fs1]*fold*L1,[-80 5],'k:'); +% plot ([fg1 fg1]*fold*L1,[-80 5],'k-'); +axis ([0 fold*L1/2 -80 5]); +xlabel('F [Hz]'); +title('filtr I'); + +%filtr II +figure(4) +plot(F2,20*log10(abs(H2))); +hold on; +plot ([fp2 fp2]*fold*L1/M1*L2,[-80 5],'k--'); +plot ([fs2 fs2]*fold*L1/M1*L2,[-80 5],'k:'); +% plot ([fg2 fg2],[-80 5],'k-'); +axis ([0 fold*L1/M1*L2/2 -80 5]); +xlabel('F [Hz]'); +title('filtr II'); + +%filtr III +figure(5) +plot(F33,20*log10(abs(H3))); +hold on; +plot ([fp3 fp3]*fold*L1/M1*L2/M2*L3,[-100 5],'k--'); +plot ([fs3 fs3]*fold*L1/M1*L2/M2*L3,[-100 5],'k:'); +% plot ([fg3 fg3],[-100 5],'k-'); +axis ([0 fold*L1/M1*L2/M2*L3/2 -100 5]); +xlabel('F [Hz]'); +title('filtr III'); + +%Filtr zbiorczy +h3L = zeros(1,length(h3)*M2*M1); +h3L(1:M2*M1:length(h3)*M2*M1)= h3; + +h2L = zeros(1,length(h2)*M1*L3); +h2L(1:M1*L3:length(h2)*M1*L3)= h2; + +h1L = zeros(1,length(h1)*L2*L3); +h1L(1:L2*L3:length(h1)*L2*L3)= h1; + +t = conv(conv(h1L, h2L), h3L); + + +figure(6) +[H2L] = freqz(h2L/L2, 1, 8192*32, fold*L); +[H1L] = freqz(h1L/L1, 1, 8192*32, fold*L); +[H3L] = freqz(h3L/L3, 1, 8192*32, fold*L); +[H12, F212] = freqz(t/L, 1, 8192*32, fold*L); +subplot(2,1,1); +plot(F212,20*log10(abs(H1L))); +hold on +plot(F212,20*log10(abs(H2L)), 'r'); +plot(F212,20*log10(abs(H3L)), 'k'); +hold off +axis ([0 fold*L/2 -80 5]); +xlabel('F [Hz]'); +title('charakterystyki filtrów sk³adowych po przeniesieniu ich na szybkoœæ Fp1'); +subplot(2,1,2); +plot(F212,20*log10(abs(H12))); +axis ([0 fold*L/2 -80 5]); +xlabel('F [Hz]'); +title('charakterystyka zbiorcza'); + + + +for i=2:6, + set(i, 'color', 'w'); +end + + + + + +end \ No newline at end of file diff --git a/Ex3/matlab/id_4.m b/Ex3/matlab/id_4.m new file mode 100644 index 0000000000000000000000000000000000000000..1daa5bb293c6cb6c959275ccecfe9d684d221045 --- /dev/null +++ b/Ex3/matlab/id_4.m @@ -0,0 +1,235 @@ +function N = id_4(nr_sygnalu, fold, fnew, Li, Mi, FPi, FSi) + +L = fnew / gcd(fold, fnew); +M = fold / gcd(fold, fnew); + +L1 = Li(1); +M1 = Mi(1); +L2 = Li(2); +M2 = Mi(2); +L3 = Li(3); +M3 = Mi(3); +L4 = Li(4); +M4 = Mi(4); + +fp1 = FPi(1); +fs1 = FSi(1); +fp2 = FPi(2); +fs2 = FSi(2); +fp3 = FPi(3); +fs3 = FSi(3); +fp4 = FPi(4); +fs4 = FSi(4); + + +%obliczanie granic pasma przepustowego i pasma zaporowego +% fg1 = (min(0.5/L,0.5/M)*fnew)/(fold*L1); +% fg2 = (min(0.5/L,0.5/M)*fnew)/(fold*L1*L2/M1); +% fg3 = (min(0.5/L,0.5/M)*fnew)/(fold*L1*L2*L3/(M1*M2)); +% fg4 = (min(0.5/L,0.5/M)*fnew)/(fold*L1*L2*L3*L4/(M1*M2*M3)); + + +%definiowanie sygna³u testowego +x = gen_signal(nr_sygnalu, fold, L, M); + +%obliczanie zafalowan w pasmach przepustowym i zaporowym +Ap = 0.1; +dp = -((1-10^(Ap/20))/(1+10^(Ap/20))); +As = 60; +ds = 10^(-As/20); + + +%uzupe³nianie zerami I stopien (interpolacja – wstawiamy L1-1 zer pomiedzy ka¿d¹ parê próbek) +xx = zeros(1,L1*length(x)); +xx(1:L1:length(x)*L1)=x; + +[nn1,fo1,mo1,w1] = remezord( [fp1 fs1], [1 0], [dp/4 ds], 1); +if nn1 < 3, nn1=3; end; +[nn,fo,mo,w] = remezord( [fp2 fs2], [1 0], [dp/4 ds], 1); +if nn < 3, nn=3; end; +[nn3,fo3,mo3,w3] = remezord( [fp3 fs3], [1 0], [dp/4 ds], 1); +if nn3 < 3, nn3=3; end; +[nn4,fo4,mo4,w4] = remezord( [fp4 fs4], [1 0], [dp/4 ds], 1); +if nn4 < 3, nn4=3; end; + +N = [ nn1+1, nn+1, nn3+1, nn4+1 ]; +if sum(N) > 1000, + disp('wymagany sumaryczny rz¹d filtrów > 1000') + return +end + +%projektowanie filtru +h1 = L1*remez(nn1,fo1,mo1,w1); +[H1, F21] = freqz(h1/L1, 1, 8192*32, fold*L1); + +%splot sygna³u po interpolacji z odpowiedzi¹ impulsow¹ filtru stopien I +y = conv(h1,xx); + +% usuwanie stanu przejsciowego i decymacja sygba³u - wybieramy co M1-ta +% probke +p = length(h1)-1; +yy=y(p+1:M1:end); + +%uzupe³nianie zerami stopien II +xx2 = zeros(1,L2*L1*length(x)/M1); +xx2(1:L2:length(x)*L2*L1/M1)=yy; + +%projektowanie filtru stopien II +h2 = L2*remez(nn,fo,mo,w); +[H2, F2] = freqz(h2/L2, 1, 8192*32, fold*L1/M1*L2); + +%splot sygna³u po interpolacji z odpowiedzi¹ impulsow¹ filtru stopien II +y2 = conv(h2,xx2); + +% usuwanie stanu przejsciowego i decymacja sygba³u - wybieramy co M2-ta +% probke +p2 = length(h2)-1; +yy2=y2(p2+1:M2:end); + +%uzupe³nianie zerami stopien III +xx3 = zeros(1,L3*(L2/M2)*(L1/M1)*length(x)); +xx3(1:L3:length(x)*(L1/M1)*(L2/M2)*L3)=yy2; + +%projektowanie filtru +h3 = L3*remez(nn3,fo3,mo3,w3); +[H3, F33] = freqz(h3/L3, 1, 8192*32, fold*L1/M1*L2/M2*L3); + +%splot sygna³u po interpolacji z odpowiedzi¹ impulsow¹ filtru stopien III +y3 = conv(h3,xx3); + +% usuwanie stanu przejsciowego i decymacja sygba³u - wybieramy co M3-ta +% probke +p3 = length(h3)-1; +yy3=y3(p3+1:M3:end); + +%uzupe³nianie zerami stopien IV +xx4 = zeros(1,L4*(L3/M3)*(L2/M2)*(L1/M1)*length(x)); +xx4(1:L4:length(x)*(L1/M1)*(L2/M2)*(L3/M3)*L4)=yy3; + +%projektowanie filtru IV +h4 = L4*remez(nn4,fo4,mo4,w4); +[H4, F44] = freqz(h4/L4, 1, 8192*32, fold*L1/M1*L2/M2*L3/M3*L4); + +%splot sygna³u po interpolacji z odpowiedzi¹ impulsow¹ filtru stopien IV +y4 = conv(h4,xx4); + +% usuwanie stanu przejsciowego i decymacja sygba³u - wybieramy co M4-ta +% probke +p4 = length(h4)-1; +yy4=y4(p4+1:M4:end); + + +%wykresy +%widmo sygna³u wejœciowego +wind0 = blackman(length(x)); +Y0 = 20*log10(abs(fftshift(fft(wind0'.*x,32768)))); +F_Y0 = linspace(-fold/2, fold/2, 32768+1); F_Y0(end) = []; +figure(2) +subplot(1,2,1); +plot(F_Y0, Y0); +set(gca, 'xlim', [-fold/2, fold/2]); +xlabel('F [Hz]'); +title('syg. wejsciowy'); + +%widmo sygba³u wyjsciowego +figure(2) +subplot(1,2,2); +wind1 = blackman(length(yy4)); +Y1 = 20*log10(abs(fftshift(fft(wind1'.*yy4,32768)))); +F_Y1 = linspace(-fnew/2, fnew/2, 32768+1); F_Y1(end) = []; +plot(F_Y1, Y1); +set(gca, 'xlim', [-fnew/2, fnew/2]); +xlabel('F [Hz]'); +title('syg. wyjsciowy'); + + +%filtr I +figure(3) +plot(F21,20*log10(abs(H1))); +hold on; +plot ([fp1 fp1]*fold*L1,[-80 5],'k--'); +plot ([fs1 fs1]*fold*L1,[-80 5],'k:'); +% plot ([fg1 fg1],[-80 5],'k-'); +axis ([0 fold*L1/2 -80 5]); +xlabel('F [Hz]'); +title('filtr I'); + +%filtr II +figure(4) +plot(F2,20*log10(abs(H2))); +hold on; +plot ([fp2 fp2]*fold*L1/M1*L2,[-80 5],'k--'); +plot ([fs2 fs2]*fold*L1/M1*L2,[-80 5],'k:'); +% plot ([fg2 fg2],[-80 5],'k-'); +axis ([0 fold*L1/M1*L2/2 -80 5]); +xlabel('F [Hz]'); +title('filtr II'); + +%filtr III +figure(5) +plot(F33,20*log10(abs(H3))); +hold on; +plot ([fp3 fp3]*fold*L1/M1*L2/M2*L3,[-100 5],'k--'); +plot ([fs3 fs3]*fold*L1/M1*L2/M2*L3,[-100 5],'k:'); +% plot ([fg3 fg3]*fold*L1/M1*L2/M2*L3,[-100 5],'k-'); +axis ([0 fold*L1/M1*L2/M2*L3/2 -100 5]); +xlabel('F [Hz]'); +title('filtr III'); + +%filtr IV +figure(6) +plot(F44,20*log10(abs(H4))); +hold on; +plot ([fp4 fp4]*fold*L1/M1*L2/M2*L3/M3*L4,[-80 5],'k--'); +plot ([fs4 fs4]*fold*L1/M1*L2/M2*L3/M3*L4,[-80 5],'k:'); +% plot ([fg4 fg4],[-80 5],'k-'); +axis ([0 fold*L1/M1*L2/M2*L3/M3*L4/2 -80 5]); +xlabel('F [Hz]'); +title('filtr IV'); + +%filtr zbiorczy +%Zbiorczy +h4L = zeros(1,length(h4)*M3*M2*M1); +h4L(1:M3*M2*M1:length(h4)*M2*M1*M3)= h4; + +h3L = zeros(1,length(h3)*M2*M1*L4); +h3L(1:M2*M1*L4:length(h3)*M2*M1*L4)= h3; + +h2L = zeros(1,length(h2)*M1*L3*L4); +h2L(1:M1*L3*L4:length(h2)*M1*L3*L4)= h2; + +h1L = zeros(1,length(h1)*L2*L3*L4); +h1L(1:L2*L3*L4:length(h1)*L2*L3*L4)= h1; + +t = conv(conv(conv(h1L, h2L), h3L), h4L); + + +figure(7) +[H2L] = freqz(h2L/L2, 1, 8192*32, fold*L); +[H1L] = freqz(h1L/L1, 1, 8192*32, fold*L); +[H3L] = freqz(h3L/L3, 1, 8192*32, fold*L); +[H4L] = freqz(h4L/L4, 1, 8192*32, fold*L); +[H12, F212] = freqz(t/L, 1, 8192*32, fold*L); +subplot(2,1,1); +plot(F212,20*log10(abs(H1L)), 'b'); +hold on +plot(F212,20*log10(abs(H2L)), 'r'); +plot(F212,20*log10(abs(H3L)), 'k'); +plot(F212,20*log10(abs(H4L)), 'g'); +hold off +axis ([0 fold*L/2 -80 5]); +xlabel('F [Hz]'); +title('charakterystyki filtrów sk³adowych po przeniesieniu ich na szybkoœæ Fp1'); +subplot(2,1,2); +plot(F212,20*log10(abs(H12))); +axis ([0 fold*L/2 -80 5]); +xlabel('F [Hz]'); +title('charakterystyka zbiorcza'); + +for i=2:7, + set(i, 'color', 'w'); +end + + + +end \ No newline at end of file diff --git a/Ex3/matlab/rcos4.m b/Ex3/matlab/rcos4.m new file mode 100644 index 0000000000000000000000000000000000000000..233f780cb878f5515966b551eeb2edbad8a56cda --- /dev/null +++ b/Ex3/matlab/rcos4.m @@ -0,0 +1,51 @@ +function h_rc=rcos4(N,L, r) +%square root raised cosine + +fp=1000; + +if nargin==2, + r=0.5; +end + +n=(0:N-1)-(N-1)/2; +% t=n/fp; T=L/fp; + +% % L=pi*L; h_rc=sinc(pi*n/L).*cos(pi*r*n/L)./(L-4*(r.^2)*(n.^2)/L); +% h_rc=sinc(t/T).*cos(r*pi*t/T)./(1-4*(r.^2)*(t.^2)/T.^2); +h_rc=(1-r)*sinc((1-r)*n/L) + ... + r*( sinc(r*n/L+1/4).*cos(pi*(n/L+1/4)) + ... + sinc(r*n/L-1/4).*cos(pi*(n/L-1/4)) ); +% % h_rc= 4*r* ( cos((1+r)*pi*n/L) + sin((1-r)*pi*n/L)./(4*r*n/L)) ... +% % ./ (pi*sqrt(1/L)*(1-(4*r*n/L).^2)); +% +ind=~isfinite(h_rc); +h_rc(ind)=0; + +if nargout==0, + figure(1) + subplot(3,1,1) + stem(n/L,h_rc) + subplot(3,1,2) + n=-(N-1):(N-1); +% size(n) +% size(conv(h_rc,h_rc)) + stem(n/L,conv(h_rc,h_rc)) + subplot(3,1,3) + H=freqz(h_rc,1,2048, 'whole'); + H=abs(H(1:end/2)); + f=linspace(0,1000,length(H)); + plot(f,H) + + H=freqz(ones(1,L),1,2048, 'whole'); + H=abs(H(1:end/2)); + f=linspace(0,1000,length(H)); + hold on + plot(f,H,'k') + hold off + H=freqz(conv(h_rc,h_rc)/L,1,2048, 'whole'); + H=abs(H(1:end/2)); + f=linspace(0,1000,length(H)); + hold on + plot(f,H,'m') + hold off +end \ No newline at end of file diff --git a/Ex3/matlab/readaudiofile.m b/Ex3/matlab/readaudiofile.m new file mode 100644 index 0000000000000000000000000000000000000000..825a9a890d520cb59e3dda822abed693cc2fc262 --- /dev/null +++ b/Ex3/matlab/readaudiofile.m @@ -0,0 +1,215 @@ +function [x, Fs] = readaudiofile(filename, param) +% [x, Fs] = readaudiofile(filename, param) +% +% returns vector x of the size SIZE=[samples channels]. +% eg. x = x(:,1) + j*x(:,2); +% +% special uses: +% param == 'size': returns SIZE in x +% param == 'cplx': for stereo files returns x as a complex vector instead of matrix +% +% supported file types: +% *.flt +% *.wav +% *.tape +% last modification: 2021.03.29 +% Author: Marek Blok + +return_cplx = 0; +if nargin == 1, + param = inf; +else + if strcmp(param, 'cplx') == 1, + return_cplx = 1; + param = inf; + end +end + +ind = find(filename == '.'); +if length(ind) == 0, + file_type = 'w'; % *.wav +else + ind = ind(end); + + temp = filename(ind+1:end); + + file_type = 'u'; % unknown format + if strcmp(temp, 'flt') == 1, + file_type = 'f'; % two channel floting point + elseif strcmp(temp, 'wav') == 1, + file_type = 'w'; % *.wav + elseif strcmp(temp, 'tape') == 1, + file_type = 't'; % *.tape + end +end + +switch file_type, + case 'w', + if strcmp(param, 'size') == 1, + if exist('audioread','file') == 0 + x = wavread(filename, 'size'); + % siz = [samples channels]. + else + info = audioinfo(filename); + x = [info.TotalSamples, info.NumChannels]; + Fs = info.SampleRate; + end + else + if isfinite(param) + if exist('audioread','file') == 0 + [x, Fs] = wavread(filename, param); + else + if length(param) == 1 + param = [1, param]; + end + [x, Fs] = audioread(filename, param); + end + else + if exist('audioread','file') == 0 + [x, Fs] = wavread(filename); + else + [x, Fs] = audioread(filename); + end + end + end + + case 't' + plik = fopen(filename, 'rb'); + if plik == -1, + error('File does not exist !!!'); + end + + header.size = fread(plik, 1, 'uint32', 0) + 4; + + header.fname = char(fread(plik, 256, 'char', 0).'); + header.cfg_fname = char(fread(plik, 256, 'char', 0).'); + header.sw_rev = fread(plik, 1, 'uint32', 0); + header.hw_rev = fread(plik, 1, 'uint32', 0); + header.file_ = fread(plik, 1, 'uint32', 0); + header.tape_type = fread(plik, 1, 'uint32', 0); + header.start_time = fread(plik, 1, 'int32', 0); % time_t + header.end_time = fread(plik, 1, 'int32', 0); % time_t + + header.total_samples = fread(plik, 1, 'uint32', 0); + file_length = header.total_samples * 4 + header.size + header.current_sample = fread(plik, 1, 'uint32', 0); + header.loop_start = fread(plik, 1, 'int64', 0); + header.loop_end = fread(plik, 1, 'int64', 0); + header.loop = fread(plik, 1, 'int32', 0); + header.group_size_32 = fread(plik, 1, 'uint32', 0); + header.block_size = fread(plik, 1, 'uint32', 0); + header.block_count = fread(plik, 1, 'uint32', 0); + header.fifo_size = fread(plik, 1, 'uint32', 0); + + + header.comment = char(fread(plik, 256, 'char', 0).'); + header.tmp = char(fread(plik, 20, 'char', 0).'); % time_t + header.status = fread(plik, 1, 'uint32', 0); + header.timestamps = fread(plik, 1, 'int32', 0); + header.freq = fread(plik, 1, 'float', 0); + header.cplx_datarate = fread(plik, 1, 'float', 0); + +% ftell(plik) + header.reserved = fread(plik, 128, 'uint32', 0); +% header.reserved.' + + header + ftell(plik) + + header.sample_type = 2; + header.ch_no = 2; + header.Fs = NaN; + + sample_type = 'int16'; + sample_size = 2; + + header_size = header.size; + if strcmp(param, 'size') == 1, + fseek(plik, 0, 'eof'); + size = (ftell(plik) - header_size) / sample_size / header.ch_no; % sizeof(float) *2 + x = size; + else + fseek(plik, header_size, 'bof'); + + len = param(1); + if length(param) > 1, + fseek(plik, sample_size*header.ch_no*(param(1)-1), 'cof'); + len = param(2) - param(1) + 1; + end + +% x = fread(plik, [header.ch_no, len], sample_type); + x = fread(plik, [header.ch_no, len], sample_type, 0); + x = x.'; + end + fclose(plik); + + case 'f' + plik = fopen(filename, 'rb'); + if plik == -1, + error('File does not exist !!!'); + end + + % 3 B - wersja pliku (w tym typ próbek) + % 1 B - liczba kana³ów + % 4 B - szybkoœæ próbkowania + header_size = 8; + header.ver = fread(plik, 1, 'uint8'); + header.sample_type = fread(plik, 1, 'uint16'); + header.ch_no = fread(plik, 1, 'uint8'); + header.Fs = fread(plik, 1, 'uint32'); + + Fs = header.Fs; + + switch (header.ver), + case 0, + switch (header.sample_type), + case 0, + sample_type = 'float'; + sample_size = 4; + case 1, + sample_type = 'uchar'; + sample_size = 1; + case 2, + sample_type = 'short'; + sample_size = 2; + case 3, + sample_type = 'int'; + sample_size = 4; + otherwise + error('Unsupported *.flt sample type !!!'); + end + otherwise + error('Unsupported *.flt file version !!!'); + end + + + if strcmp(param, 'size') == 1, + fseek(plik, 0, 'eof'); + size = (ftell(plik) - header_size) / sample_size / header.ch_no; % sizeof(float) *2 + x = size; + else + len = param(1); + status = 0; + if length(param) > 1, + status = fseek(plik, sample_size*header.ch_no*(param(1)-1), 'cof'); + len = param(2) - param(1) + 1; + end + + if (status == -1) + x = []; + else + x = fread(plik, [header.ch_no, len], sample_type); + x = x.'; + end + end + + fclose(plik); + otherwise + error('Unsupported file format !!!'); +end + +if return_cplx == 1, + if length(x(1,:)) == 2, + x = x(:,1) + j*x(:,2); + end +end \ No newline at end of file diff --git a/Ex3/matlab/save_filter_coef.m b/Ex3/matlab/save_filter_coef.m new file mode 100644 index 0000000000000000000000000000000000000000..8cf1f072079de9ee5dab70dc9682ae0ae00ef1df --- /dev/null +++ b/Ex3/matlab/save_filter_coef.m @@ -0,0 +1,226 @@ +function save_filter_coef(filename, coefficients, file_version) +% save_filter_coef(filename, coefficients [, file_version]) +% +% FIR filter coefficients +% coefficients.h +% - can be cell vector to store multiple FIR impulse responces +% - if any of the impulse responses is complex then all responses will +% be stored as complex +% IIR filter coefficients +% coefficients.a +% coefficients.b +% +% For file_version >= 1 (default == 0), +% coefficients.Fp - sampling frequency +% +% This file is a part of Digital Signal Processing Engine +% +% File format (*.coef) - this is open format, for general use +% * (not only for storing coefficients) +% +% File format (*.h) - this is C++ header file for DSPElib with hardcoded *.coef equivalent +% +% \author Marek Blok +% \date 2020.02.22 + +if nargin == 2, + file_version = 0; +end + +ind = find(filename == '.'); +if length(ind) == 0, + filename = [filename, '.coef']; +end + +% detect mode based on file extention +[PATHSTR,NAME,EXT] = fileparts(filename); +switch EXT + case '.h' + mode = 'h-file'; + plik = fopen(filename, 'wt'); + + case '.coef' + mode = 'coefs-file'; + plik = fopen(filename, 'wb'); + + otherwise + mode = 'unknown-file'; + error(mode); +end + +switch mode + case 'h-file' + fprintf(plik, '// save_filter_coef output (hard coded coefficients)\n'); + fprintf(plik, '#pragma once\n'); + fprintf(plik, '#include <DSP_lib.h>\n'); + fprintf(plik, '\n'); + + if isfield(coefficients, 'h'), + h = coefficients.h; + + for ind_h = 0:length(h)-1 + fprintf(plik, 'DSP_float_vector Farrow_coefs_row_%i = {', ind_h); + h_tmp = h{ind_h+1}; + for ind_p = 0:length(h_tmp)-1, + if ind_p > 0 + fprintf(plik, ', '); + end + fprintf(plik, '%.15ff', h_tmp(ind_p+1)); + end + %0.1f, 0.2f, 0.1f + fprintf(plik, '};\n'); + end + fprintf(plik, '\n'); + + %vector <DSP_float_vector> Farrow_coefs = { coefs_0, coefs_1, coefs_2 }; + fprintf(plik, 'vector <DSP_float_vector> Farrow_coefs = {'); + for ind_h = 0:length(h)-1 + if ind_h > 0 + fprintf(plik, ', '); + end + if (ind_h < length(h_tmp)) & (rem(ind_h, 5) == 0) + fprintf(plik, '\n '); + end + fprintf(plik, 'Farrow_coefs_row_%i', ind_h); + end + fprintf(plik, '\n };\n'); + + fprintf(plik, '\n'); + fprintf(plik, 'const unsigned int p_Farrow = %i; // should be equal to Farrow_coefs[0].size()-1\n', length(h{1})-1); + fprintf(plik, 'const unsigned int N_FSD = %i; // should be equal to Farrow_coefs.size()\n', length(h)); + end + + if isfield(coefficients, 'b'), + fclose all; + error('unsupported: coefficients.b'); + end + if isfield(coefficients, 'a'), + fclose all; + error('unsupported: coefficients.a'); + end + + case 'coefs-file' + % * - (uchar) 1B - file version number + fwrite(plik, file_version, 'uchar'); + + switch file_version, + case 0, + case 1, + % * - (uint) 4B - Sampling frequency + if isfield(coefficients, 'Fp'), + fwrite(plik, coefficients.Fp, 'uint32'); + else + fclose(plik); + error('Input data does not contain Fp'); + end + otherwise, + fclose(plik); + error('This version of coefficients file is unsupported'); + end + + if isfield(coefficients, 'h'), + isFIR = 1; + if iscell(coefficients.h) + resp_no = length(coefficients.h); + % if resp_no = 1; + % coefficients.h = coefficients.h{1}; + % end + else + resp_no = 1; + end + if resp_no == 1, + isComplex = any(imag(coefficients.h(:))); + else + isComplex = false; + for ind_resp = 1:resp_no, + isComplex = isComplex | any(imag(coefficients.h{ind_resp}(:))); + end + end + else + isFIR = 0; + isComplex = any(imag(coefficients.a(:))) | any(imag(coefficients.b(:))); + end + + % * - data - coefficients data (depends on fle version) + % * . + % * Data segment format: + % * -# (version: 0x00) + % * - (uchar) 1B - number of sample dimensions + % * 1 - real, 2 - complex, ... + if isComplex, + fwrite(plik, 2, 'uchar'); % complex + else + fwrite(plik, 1, 'uchar'); % real + end + % * - (uchar) 1B - sample component type + % * - DSP_FT_float (=1) : C++ float (32bit floating point) + % * - DSP_FT_short (=2) : C++ short (16bit signed integer) + % * - DSP_FT_uchar (=3) : C++ unsigned char (8bit unsigned integer with bias (0x80)) + % * - DSP_FT_double (=7) : C++ double (64bit floating point) + % * - DSP_FT_long_double (=8) : C++ long double (80bit floating point) + fwrite(plik, 1, 'uchar'); + + % * - (uchar) 1B - number of vectors + % * - 1 - FIR filter coefficients (one vector) + % * - 2 - IIR filter coefficients (two vectors) + % * - (x number of vectors) + % * - (ushort) 2B - number of samples in vector + % * - (x number of samples) + % * - (x number of sample dimensions) + % * - (sample componet type) xB - sample component + % * e.g. real, imag part + if isFIR, + fwrite(plik, resp_no, 'uchar'); + + if iscell(coefficients.h) + for ind_resp = 1:resp_no, + N_FIR = length(coefficients.h{ind_resp}); + fwrite(plik, N_FIR, 'uint16'); + if isComplex, + dane(1:2:2*N_FIR) = real(coefficients.h{ind_resp}); + dane(2:2:2*N_FIR) = imag(coefficients.h{ind_resp}); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.h{ind_resp}), 'float'); + end + end + else + N_FIR = length(coefficients.h); + fwrite(plik, N_FIR, 'uint16'); + if isComplex, + dane(1:2:2*N_FIR) = real(coefficients.h); + dane(2:2:2*N_FIR) = imag(coefficients.h); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.h), 'float'); + end + end + + else + fwrite(plik, 2, 'uchar'); + + N_a = length(coefficients.a); + fwrite(plik, N_a, 'uint16'); + if isComplex, + dane(1:2:2*N_a) = real(coefficients.a); + dane(2:2:2*N_a) = imag(coefficients.a); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.a), 'float'); + end + + + N_b = length(coefficients.b); + fwrite(plik, N_b, 'uint16'); + if isComplex, + dane(1:2:2*N_b) = real(coefficients.b); + dane(2:2:2*N_b) = imag(coefficients.b); + fwrite(plik, dane, 'float'); + else + fwrite(plik, real(coefficients.b), 'float'); + end + end + +end +fclose(plik); + diff --git a/Ex3/rundot.bat b/Ex3/rundot.bat new file mode 100644 index 0000000000000000000000000000000000000000..583ca19213d6aed305520b0bdf1eb346be38fb35 --- /dev/null +++ b/Ex3/rundot.bat @@ -0,0 +1,4 @@ +path = "D:\Program Files (x86)\Graphviz\bin";%path% + +del Ex3_task3.gif +dot -Tgif Ex3_task3.dot -oEx3_task3.gif