T-Echo Card audio support initial stages - codec2 attempts

This commit is contained in:
pelgraine
2026-05-07 05:47:18 +10:00
parent 4b734f1bac
commit 708b96e0e8
109 changed files with 87144 additions and 24 deletions
+3 -1
View File
@@ -322,7 +322,9 @@ private:
AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table
int next_ack_idx;
#define ADVERT_PATH_TABLE_SIZE 1000
#ifndef ADVERT_PATH_TABLE_SIZE
#define ADVERT_PATH_TABLE_SIZE 1000
#endif
AdvertPath* advert_paths; // PSRAM-allocated in begin(), size = ADVERT_PATH_TABLE_SIZE
// Sent message repeat tracking
+72 -5
View File
@@ -894,7 +894,7 @@
#endif
// --- T-Echo Lite: CardKB keyboard, GxEPD2 e-ink, no touch ---
#if defined(LILYGO_TECHO_LITE)
#if defined(LILYGO_TECHO_LITE) || defined(LILYGO_TECHO_CARD)
#include "ContactsScreen.h"
#include "ChannelScreen.h"
#include "ChannelPickerScreen.h"
@@ -904,6 +904,12 @@
#include "LastHeardScreen.h"
#include "PathEditorScreen.h"
#ifdef LILYGO_TECHO_CARD
#include "TechoCardHomeScreen.h"
static TechoCardHomeScreen* _techoHome = nullptr;
static int _techoC2Debug = 0;
#endif
#ifdef MECK_CARDKB
#include "CardKBKeyboard.h"
static CardKBKeyboard cardkb;
@@ -1027,8 +1033,8 @@ static uint32_t _atoi(const char* sp) {
/* GLOBAL OBJECTS */
#ifdef DISPLAY_CLASS
#include "UITask.h"
#if HAS_GPS
#include "MapScreen.h" // After BLE PNGdec headers conflict with BLE if included earlier
#if HAS_GPS && !defined(LILYGO_TECHO_CARD)
#include "MapScreen.h" // After BLE -- PNGdec headers conflict with BLE if included earlier
#endif
UITask ui_task(&board, &serial_interface);
#endif
@@ -2101,6 +2107,16 @@ void setup() {
MESH_DEBUG_PRINTLN("setup() - about to call ui_task.begin()");
ui_task.begin(disp, &sensors, the_mesh.getNodePrefs());
MESH_DEBUG_PRINTLN("setup() - ui_task.begin() done");
// T-Echo Card: replace the generic HomeScreen with the 72x40 OLED home screen
#ifdef LILYGO_TECHO_CARD
{
_techoHome = new TechoCardHomeScreen(&ui_task, &rtc_clock,
the_mesh.getNodePrefs());
ui_task.setHomeScreen(_techoHome);
MESH_DEBUG_PRINTLN("setup() - TechoCardHomeScreen installed");
}
#endif
#endif
// ---------------------------------------------------------------------------
@@ -2387,6 +2403,12 @@ void setup() {
Serial.printf("setup() complete - free heap: %d, largest block: %d\n",
ESP.getFreeHeap(), ESP.getMaxAllocHeap());
#endif
{
void* p25 = malloc(25000); void* p10 = malloc(10000); void* p4 = malloc(4000);
Serial.printf("setup() heap probe: 25K=%s 10K=%s 4K=%s\n",
p25?"yes":"no", p10?"yes":"no", p4?"yes":"no");
if (p4) free(p4); if (p10) free(p10); if (p25) free(p25);
}
MESH_DEBUG_PRINTLN("=== setup() - COMPLETE ===");
}
@@ -2414,10 +2436,49 @@ void otaResumeRadio() {
#endif
void loop() {
// T-Echo Card: lazy Codec2 init from shallow stack context.
// codec2_create needs ~3KB stack for FFT/trig init. The loop task
// has only 4KB total. Calling from render() (deep call chain) overflows.
// Calling from here (top of loop) works because stack depth is minimal.
#ifdef LILYGO_TECHO_CARD
if (_techoHome && _techoHome->needsCodec2()) {
void* probe = malloc(25000);
Serial.printf("Voice: heap probe 25K=%s, creating codec2...\n", probe?"yes":"no");
if (probe) free(probe);
Serial.flush();
struct CODEC2* c2 = codec2_create(VC_C2_MODE);
Serial.printf("Voice: codec2_create returned %p\n", c2);
Serial.flush();
if (c2) {
_techoHome->setCodec2Instance(c2);
void* postProbe = malloc(1000);
Serial.printf("Voice: set OK, post-probe=%s\n", postProbe?"yes":"no");
if (postProbe) free(postProbe);
Serial.flush();
_techoC2Debug = 99999; // Keep printing to test if yields prevent crash
}
}
#endif
#ifdef MECK_OTA_UPDATE
if (!otaRadioPaused) {
#endif
#ifdef LILYGO_TECHO_CARD
if (_techoC2Debug > 0) {
Serial.print("[pre-mesh]"); Serial.flush();
}
#endif
the_mesh.loop();
#ifdef LILYGO_TECHO_CARD
if (_techoC2Debug > 0) {
Serial.print("[post-mesh]"); Serial.flush();
}
#endif
#ifdef MECK_OTA_UPDATE
} else {
// OTA/File Manager active — poll the web server from the main loop for fast response.
@@ -2457,7 +2518,7 @@ void loop() {
// Map screen: periodically update own GPS position and contact markers
#ifdef DISPLAY_CLASS
#if HAS_GPS
#if HAS_GPS && !defined(LILYGO_TECHO_CARD)
if (ui_task.isOnMapScreen()) {
static unsigned long lastMapUpdate = 0;
if (millis() - lastMapUpdate > 30000) { // Every 30 seconds
@@ -2927,7 +2988,13 @@ void loop() {
}
}
#else
#ifdef LILYGO_TECHO_CARD
if (_techoC2Debug > 0) { Serial.print("[pre-ui]"); Serial.flush(); }
#endif
ui_task.loop();
#ifdef LILYGO_TECHO_CARD
if (_techoC2Debug > 0) { Serial.print("[post-ui]"); Serial.flush(); _techoC2Debug--; }
#endif
#endif
#endif
rtc_clock.tick();
@@ -3601,7 +3668,7 @@ void loop() {
}
#endif
// Low-power loop throttle yield CPU when lock screen is active.
// Low-power loop throttle -- yield CPU when lock screen is active.
// The RTOS idle task executes WFI (wait-for-interrupt) during delay(),
// dramatically reducing CPU power draw. 50 ms gives 20 loop cycles/sec
// which is ample for LoRa packet reception (radio has hardware FIFO).
@@ -2814,9 +2814,11 @@ public:
} else if (type == ROW_GPS_BAUD) {
_editPickerIdx--;
if (_editPickerIdx < 0) _editPickerIdx = GPS_BAUD_OPTION_COUNT - 1;
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
} else if (type == ROW_AUTO_LOCK) {
_editPickerIdx--;
if (_editPickerIdx < 0) _editPickerIdx = AUTO_LOCK_OPTION_COUNT - 1;
#endif
} else if (type == ROW_FONT_STYLE) {
_editPickerIdx--;
if (_editPickerIdx < 0) _editPickerIdx = MECK_FONT_STYLE_COUNT - 1;
@@ -2835,9 +2837,11 @@ public:
} else if (type == ROW_GPS_BAUD) {
_editPickerIdx++;
if (_editPickerIdx >= GPS_BAUD_OPTION_COUNT) _editPickerIdx = 0;
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
} else if (type == ROW_AUTO_LOCK) {
_editPickerIdx++;
if (_editPickerIdx >= AUTO_LOCK_OPTION_COUNT) _editPickerIdx = 0;
#endif
} else if (type == ROW_FONT_STYLE) {
_editPickerIdx++;
if (_editPickerIdx >= MECK_FONT_STYLE_COUNT) _editPickerIdx = 0;
@@ -2859,12 +2863,14 @@ public:
_editMode = EDIT_NONE;
Serial.printf("Settings: GPS baud set to %lu (reboot to apply)\n",
(unsigned long)_prefs->gps_baudrate);
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
} else if (type == ROW_AUTO_LOCK) {
_prefs->auto_lock_minutes = AUTO_LOCK_OPTIONS[_editPickerIdx];
the_mesh.savePrefs();
_editMode = EDIT_NONE;
Serial.printf("Settings: Auto lock = %s\n",
autoLockLabel(_prefs->auto_lock_minutes));
#endif
} else if (type == ROW_FONT_STYLE) {
_prefs->ui_font_style = _editPickerIdx;
the_mesh.savePrefs();
+20 -11
View File
@@ -1,7 +1,7 @@
#include "UITask.h"
#include <helpers/TxtDataHelpers.h>
#include "../MyMesh.h"
#if !defined(LILYGO_TECHO_LITE)
#if !defined(LILYGO_TECHO_LITE) && !defined(LILYGO_TECHO_CARD)
#include "NotesScreen.h"
#endif
#include "RepeaterAdminScreen.h"
@@ -11,7 +11,7 @@
#ifdef MECK_WEB_READER
#include "WebReaderScreen.h"
#endif
#if HAS_GPS
#if HAS_GPS && !defined(LILYGO_TECHO_CARD)
#include "MapScreen.h"
#endif
#include "target.h"
@@ -52,7 +52,7 @@
#include "ChannelScreen.h"
#include "ChannelPickerScreen.h"
#include "ContactsScreen.h"
#if !defined(LILYGO_TECHO_LITE)
#if !defined(LILYGO_TECHO_LITE) && !defined(LILYGO_TECHO_CARD)
#include "TextReaderScreen.h"
#endif
#include "SettingsScreen.h"
@@ -1342,7 +1342,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
((ChannelPickerScreen*)channel_picker_screen)->setChannelScreen((ChannelScreen*)channel_screen);
contacts_screen = new ContactsScreen(this, &rtc_clock);
((ContactsScreen*)contacts_screen)->setDMUnreadPtr(_dmUnread);
#if !defined(LILYGO_TECHO_LITE)
#if !defined(LILYGO_TECHO_LITE) && !defined(LILYGO_TECHO_CARD)
text_reader = new TextReaderScreen(this, node_prefs);
notes_screen = new NotesScreen(this, node_prefs);
#else
@@ -1365,7 +1365,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
#ifdef HAS_4G_MODEM
sms_screen = new SMSScreen(this, node_prefs);
#endif
#if HAS_GPS
#if HAS_GPS && !defined(LILYGO_TECHO_CARD)
map_screen = new MapScreen(this);
#else
map_screen = nullptr;
@@ -1379,6 +1379,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
#endif
// Apply saved dark mode preference (both T-Deck Pro and T5S3)
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
if (_node_prefs->dark_mode) {
::display.setDarkMode(true);
}
@@ -1387,6 +1388,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
if (_node_prefs->ui_font_style > 0) {
::display.setFontStyle(_node_prefs->ui_font_style);
}
#endif
setCurrScreen(splash);
}
@@ -1723,7 +1725,7 @@ void UITask::loop() {
c = checkDisplayOn(KEY_NEXT);
} else {
// Navigate back: reader reading→file list, file list→home, others→home
#if !defined(LILYGO_TECHO_LITE)
#if !defined(LILYGO_TECHO_LITE) && !defined(LILYGO_TECHO_CARD)
if (isOnTextReader()) {
TextReaderScreen* reader = (TextReaderScreen*)text_reader;
if (reader && reader->isReading()) {
@@ -1890,23 +1892,27 @@ if (curr) curr->poll();
_next_refresh = millis() + 500; // Re-check in 500ms
} else {
// Sync dark mode with prefs (settings toggle takes effect here)
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
if (_node_prefs && display.isDarkMode() != (_node_prefs->dark_mode != 0)) {
display.setDarkMode(_node_prefs->dark_mode != 0);
}
#endif
#if defined(LilyGo_T5S3_EPaper_Pro)
// Sync portrait mode with prefs (T5S3 only)
if (_node_prefs && display.isPortraitMode() != (_node_prefs->portrait_mode != 0)) {
display.setPortraitMode(_node_prefs->portrait_mode != 0);
// Text reader layout depends on orientation force recalculation
// Text reader layout depends on orientation -- force recalculation
if (text_reader) {
((TextReaderScreen*)text_reader)->invalidateLayout();
}
}
#endif
// Sync font style with prefs (settings toggle takes effect here)
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
if (_node_prefs && display.getFontStyle() != _node_prefs->ui_font_style) {
display.setFontStyle(_node_prefs->ui_font_style);
}
#endif
_display->startFrame();
#if defined(LilyGo_T5S3_EPaper_Pro)
if (_vkbActive) {
@@ -2425,7 +2431,7 @@ void UITask::onVKBSubmit() {
break;
}
case VKB_NOTES: {
#if !defined(LILYGO_TECHO_LITE)
#if !defined(LILYGO_TECHO_LITE) && !defined(LILYGO_TECHO_CARD)
NotesScreen* notes = (NotesScreen*)getNotesScreen();
if (notes && strlen(text) > 0) {
for (int i = 0; text[i]; i++) {
@@ -2494,7 +2500,7 @@ void UITask::onVKBSubmit() {
}
#endif
case VKB_TEXT_PAGE: {
#if !defined(LILYGO_TECHO_LITE)
#if !defined(LILYGO_TECHO_LITE) && !defined(LILYGO_TECHO_CARD)
if (strlen(text) > 0) {
int pageNum = atoi(text);
TextReaderScreen* reader = (TextReaderScreen*)getTextReaderScreen();
@@ -2735,7 +2741,7 @@ void UITask::gotoContactsScreen() {
void UITask::gotoTextReader() {
if (!text_reader) return; // Not available on this platform
#if !defined(LILYGO_TECHO_LITE)
#if !defined(LILYGO_TECHO_LITE) && !defined(LILYGO_TECHO_CARD)
TextReaderScreen* reader = (TextReaderScreen*)text_reader;
if (_display != NULL) {
reader->enter(*_display);
@@ -2751,7 +2757,7 @@ void UITask::gotoTextReader() {
void UITask::gotoNotesScreen() {
if (!notes_screen) return; // Not available on this platform
#if !defined(LILYGO_TECHO_LITE)
#if !defined(LILYGO_TECHO_LITE) && !defined(LILYGO_TECHO_CARD)
NotesScreen* notes = (NotesScreen*)notes_screen;
if (_display != NULL) {
notes->enter(*_display);
@@ -3011,6 +3017,8 @@ void UITask::gotoWebReader() {
#if HAS_GPS
void UITask::gotoMapScreen() {
if (!map_screen) return; // Not available on this platform (T-Echo Card)
#if !defined(LILYGO_TECHO_CARD)
MapScreen* map = (MapScreen*)map_screen;
if (_display != NULL) {
map->enter(*_display);
@@ -3021,6 +3029,7 @@ void UITask::gotoMapScreen() {
}
_auto_off = millis() + AUTO_OFF_MILLIS;
_next_refresh = 100;
#endif
}
#endif
+1
View File
@@ -325,6 +325,7 @@ public:
NodePrefs* getNodePrefs() const { return _node_prefs; }
UIScreen* getAudiobookScreen() const { return audiobook_screen; }
void setAudiobookScreen(UIScreen* s) { audiobook_screen = s; }
void setHomeScreen(UIScreen* s) { if (home) delete home; home = s; }
#ifdef MECK_AUDIO_VARIANT
UIScreen* getAlarmScreen() const { return alarm_screen; }
void setAlarmScreen(UIScreen* s) { alarm_screen = s; }
+8
View File
@@ -0,0 +1,8 @@
{
"name": "PDM_nrf52",
"version": "1.0.0",
"description": "PDM microphone library for nRF52840 (from Adafruit BSP)",
"license": "LGPL-2.1",
"frameworks": "arduino",
"platforms": "*"
}
+261
View File
@@ -0,0 +1,261 @@
/*
PDM.cpp - library to interface with nRF52840 PDM peripheral
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2019 Arduino SA
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
#include "PDM.h"
#include <hal/nrf_pdm.h>
#include <Adafruit_TinyUSB.h> // for Serial
#define DEFAULT_PDM_GAIN 20
#define PDM_IRQ_PRIORITY 7
#define NRF_PDM_FREQ_1280K (nrf_pdm_freq_t)(0x0A000000UL) ///< PDM_CLK= 1.280 MHz (32 MHz / 25) => Fs= 20000 Hz
#define NRF_PDM_FREQ_2000K (nrf_pdm_freq_t)(0x10000000UL) ///< PDM_CLK= 2.000 MHz (32 MHz / 16) => Fs= 31250 Hz
#define NRF_PDM_FREQ_2667K (nrf_pdm_freq_t)(0x15000000UL) ///< PDM_CLK= 2.667 MHz (32 MHz / 12) => Fs= 41667 Hz
#define NRF_PDM_FREQ_3200K (nrf_pdm_freq_t)(0x19000000UL) ///< PDM_CLK= 3.200 MHz (32 MHz / 10) => Fs= 50000 Hz
#define NRF_PDM_FREQ_4000K (nrf_pdm_freq_t)(0x20000000UL) ///< PDM_CLK= 4.000 MHz (32 MHz / 8) => Fs= 62500 Hz
PDMClass::PDMClass(int dinPin, int clkPin, int pwrPin) :
_dinPin(dinPin),
_clkPin(clkPin),
_pwrPin(pwrPin),
_onReceive(NULL)
{
}
PDMClass::~PDMClass()
{
}
void PDMClass::setPins(int dataPin, int clkPin, int pwrPin)
{
_dinPin = dataPin;
_clkPin = clkPin;
_pwrPin = pwrPin;
}
int PDMClass::begin(int channels, long sampleRate)
{
_channels = channels;
// Enable high frequency oscillator if not already enabled
uint8_t sd_en = 0;
sd_softdevice_is_enabled(&sd_en);
if (sd_en)
{
uint32_t is_running;
sd_clock_hfclk_is_running(&is_running);
if (!is_running) {
sd_clock_hfclk_request();
while(!is_running) {
yield();
sd_clock_hfclk_is_running(&is_running);
}
}
}
else
{
if (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {
NRF_CLOCK->TASKS_HFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) yield();
}
}
// configure the sample rate and channels
switch (sampleRate) {
case 16000:
#ifndef NRF52832_XXAA
NRF_PDM->RATIO = ((PDM_RATIO_RATIO_Ratio80 << PDM_RATIO_RATIO_Pos) & PDM_RATIO_RATIO_Msk);
#endif
nrf_pdm_clock_set(NRF_PDM, NRF_PDM_FREQ_1280K);
break;
case 41667:
nrf_pdm_clock_set(NRF_PDM, NRF_PDM_FREQ_2667K);
break;
default:
return 0; // unsupported
}
switch (channels) {
case 2:
nrf_pdm_mode_set(NRF_PDM, NRF_PDM_MODE_STEREO, NRF_PDM_EDGE_LEFTFALLING);
break;
case 1:
nrf_pdm_mode_set(NRF_PDM, NRF_PDM_MODE_MONO, NRF_PDM_EDGE_LEFTFALLING);
break;
default:
return 0; // unsupported
}
setGain(DEFAULT_PDM_GAIN);
// configure the I/O and mux
pinMode(_clkPin, OUTPUT);
digitalWrite(_clkPin, LOW);
pinMode(_dinPin, INPUT);
nrf_pdm_psel_connect(NRF_PDM, digitalPinToPinName(_clkPin), digitalPinToPinName(_dinPin));
// clear events and enable PDM interrupts
nrf_pdm_event_clear(NRF_PDM, NRF_PDM_EVENT_STARTED);
nrf_pdm_event_clear(NRF_PDM, NRF_PDM_EVENT_END);
nrf_pdm_event_clear(NRF_PDM, NRF_PDM_EVENT_STOPPED);
nrf_pdm_int_enable(NRF_PDM, NRF_PDM_INT_STARTED | NRF_PDM_INT_STOPPED);
if (_pwrPin > -1) {
// power the mic on
pinMode(_pwrPin, OUTPUT);
digitalWrite(_pwrPin, HIGH);
}
// clear the buffer
_doubleBuffer.reset();
// set the PDM IRQ priority and enable
NVIC_SetPriority(PDM_IRQn, PDM_IRQ_PRIORITY);
NVIC_ClearPendingIRQ(PDM_IRQn);
NVIC_EnableIRQ(PDM_IRQn);
// set the buffer for transfer
// nrf_pdm_buffer_set((uint32_t*)_doubleBuffer.data(), _doubleBuffer.availableForWrite() / (sizeof(int16_t) * _channels));
// _doubleBuffer.swap();
// enable and trigger start task
nrf_pdm_enable(NRF_PDM);
nrf_pdm_event_clear(NRF_PDM, NRF_PDM_EVENT_STARTED);
nrf_pdm_task_trigger(NRF_PDM, NRF_PDM_TASK_START);
return 1;
}
void PDMClass::end()
{
// disable PDM and IRQ
nrf_pdm_disable(NRF_PDM);
NVIC_DisableIRQ(PDM_IRQn);
if (_pwrPin > -1) {
// power the mic off
digitalWrite(_pwrPin, LOW);
pinMode(_pwrPin, INPUT);
}
// Don't disable high frequency oscillator since it could be in use by RADIO
// unconfigure the I/O and un-mux
nrf_pdm_psel_disconnect(NRF_PDM);
pinMode(_clkPin, INPUT);
}
int PDMClass::available()
{
NVIC_DisableIRQ(PDM_IRQn);
size_t avail = _doubleBuffer.available();
NVIC_EnableIRQ(PDM_IRQn);
return avail;
}
int PDMClass::read(void* buffer, size_t size)
{
NVIC_DisableIRQ(PDM_IRQn);
int read = _doubleBuffer.read(buffer, size);
NVIC_EnableIRQ(PDM_IRQn);
return read;
}
void PDMClass::onReceive(void(*function)(void))
{
_onReceive = function;
}
void PDMClass::setGain(int gain)
{
nrf_pdm_gain_set(NRF_PDM, gain, gain);
}
void PDMClass::setBufferSize(int bufferSize)
{
_doubleBuffer.setSize(bufferSize);
}
void PDMClass::IrqHandler()
{
if (nrf_pdm_event_check(NRF_PDM, NRF_PDM_EVENT_STARTED)) {
nrf_pdm_event_clear(NRF_PDM, NRF_PDM_EVENT_STARTED);
if (_doubleBuffer.available() == 0) {
// switch to the next buffer
nrf_pdm_buffer_set(NRF_PDM, (uint32_t*)_doubleBuffer.data(), _doubleBuffer.availableForWrite() / (sizeof(int16_t) * _channels));
// make the current one available for reading
_doubleBuffer.swap(_doubleBuffer.availableForWrite());
// call receive callback if provided
if (_onReceive) {
_onReceive();
}
} else {
// buffer overflow, stop
nrf_pdm_disable(NRF_PDM);
}
} else if (nrf_pdm_event_check(NRF_PDM, NRF_PDM_EVENT_STOPPED)) {
nrf_pdm_event_clear(NRF_PDM, NRF_PDM_EVENT_STOPPED);
} else if (nrf_pdm_event_check(NRF_PDM, NRF_PDM_EVENT_END)) {
nrf_pdm_event_clear(NRF_PDM, NRF_PDM_EVENT_END);
}
}
extern "C"
{
void PDM_IRQHandler(void)
{
PDM.IrqHandler();
}
}
#ifndef PIN_PDM_DIN
#define PIN_PDM_DIN -1
#endif
#ifndef PIN_PDM_CLK
#define PIN_PDM_CLK -1
#endif
#ifndef PIN_PDM_PWR
#define PIN_PDM_PWR -1
#endif
PDMClass PDM(PIN_PDM_DIN, PIN_PDM_CLK, PIN_PDM_PWR);
+65
View File
@@ -0,0 +1,65 @@
/*
Copyright (c) 2019 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _PDM_H_INCLUDED
#define _PDM_H_INCLUDED
#if !defined(ARDUINO_NRF52_ADAFRUIT)
#error "This library targets only Adafruit NRF52840 boards"
#endif
#include <Arduino.h>
#include <Adafruit_TinyUSB.h> // for Serial
#include "utility/PDMDoubleBuffer.h"
class PDMClass
{
public:
PDMClass(int dataPin, int clkPin, int pwrPin);
virtual ~PDMClass();
void setPins(int dataPin, int clkPin, int pwrPin);
int begin(int channels, long sampleRate);
void end();
virtual int available();
virtual int read(void* buffer, size_t size);
void onReceive(void(*)(void));
void setGain(int gain);
void setBufferSize(int bufferSize);
// private:
void IrqHandler();
private:
int _dinPin;
int _clkPin;
int _pwrPin;
int _channels;
PDMDoubleBuffer _doubleBuffer;
void (*_onReceive)(void);
};
extern PDMClass PDM;
#endif
@@ -0,0 +1,133 @@
/*
Copyright (c) 2016 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include "PDMDoubleBuffer.h"
PDMDoubleBuffer::PDMDoubleBuffer() :
_size(DEFAULT_PDM_BUFFER_SIZE)
{
reset();
}
PDMDoubleBuffer::~PDMDoubleBuffer()
{
}
void PDMDoubleBuffer::setSize(int size)
{
_size = size;
}
void PDMDoubleBuffer::reset()
{
_buffer[0] = (uint8_t*)realloc(_buffer[0], _size);
_buffer[1] = (uint8_t*)realloc(_buffer[1], _size);
memset(_buffer[0], 0x00, _size);
memset(_buffer[1], 0x00, _size);
_index = 0;
_length[0] = 0;
_length[1] = 0;
_readOffset[0] = 0;
_readOffset[1] = 0;
}
size_t PDMDoubleBuffer::availableForWrite()
{
return (_size - (_length[_index] - _readOffset[_index]));
}
size_t PDMDoubleBuffer::write(const void *buffer, size_t size)
{
size_t space = availableForWrite();
if (size > space) {
size = space;
}
if (size == 0) {
return 0;
}
memcpy(&_buffer[_index][_length[_index]], buffer, size);
_length[_index] += size;
return size;
}
size_t PDMDoubleBuffer::read(void *buffer, size_t size)
{
size_t avail = available();
if (size > avail) {
size = avail;
}
if (size == 0) {
return 0;
}
memcpy(buffer, &_buffer[_index][_readOffset[_index]], size);
_readOffset[_index] += size;
return size;
}
size_t PDMDoubleBuffer::peek(void *buffer, size_t size)
{
size_t avail = available();
if (size > avail) {
size = avail;
}
if (size == 0) {
return 0;
}
memcpy(buffer, &_buffer[_index][_readOffset[_index]], size);
return size;
}
void* PDMDoubleBuffer::data()
{
return (void*)_buffer[_index];
}
size_t PDMDoubleBuffer::available()
{
return _length[_index] - _readOffset[_index];
}
void PDMDoubleBuffer::swap(int length)
{
if (_index == 0) {
_index = 1;
} else {
_index = 0;
}
_length[_index] = length;
_readOffset[_index] = 0;
}
@@ -0,0 +1,53 @@
/*
Copyright (c) 2016 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _PDM_DOUBLE_BUFFER_H_INCLUDED
#define _PDM_DOUBLE_BUFFER_H_INCLUDED
#include <stddef.h>
#include <stdint.h>
#define DEFAULT_PDM_BUFFER_SIZE 512
class PDMDoubleBuffer
{
public:
PDMDoubleBuffer();
virtual ~PDMDoubleBuffer();
void setSize(int size);
void reset();
size_t availableForWrite();
size_t write(const void *buffer, size_t size);
size_t read(void *buffer, size_t size);
size_t peek(void *buffer, size_t size);
void* data();
size_t available();
void swap(int length = 0);
private:
uint8_t* _buffer[2];
int _size;
volatile int _length[2];
volatile int _readOffset[2];
volatile int _index;
};
#endif
+11
View File
@@ -0,0 +1,11 @@
{
"name": "codec2_nrf52",
"version": "0.7.0",
"description": "Codec2 low-bitrate speech codec - stripped for nRF52840 (1200bps mode)",
"license": "LGPL-2.1",
"frameworks": "arduino",
"platforms": "*",
"build": {
"flags": "-DCODEC2_MODE_EN_DEFAULT"
}
}
File diff suppressed because one or more lines are too long
+29
View File
@@ -0,0 +1,29 @@
/*
FILE....: ../src/HRA_112_112.h
Static arrays for CML LDPC, generated by ldpc_gen_h_file.m.
*/
#define HRA_112_112_NUMBERPARITYBITS 112
#define HRA_112_112_MAX_ROW_WEIGHT 3
#define HRA_112_112_CODELENGTH 224
#define HRA_112_112_NUMBERROWSHCOLS 112
#define HRA_112_112_MAX_COL_WEIGHT 3
#define HRA_112_112_DEC_TYPE 0
#define HRA_112_112_MAX_ITER 100
double HRA_112_112_H_rows[] = {
22, 18, 15, 63, 16, 13, 1, 2, 29, 25, 28, 4, 36, 10, 38, 7, 60, 23, 11, 38, 28, 1, 12, 31, 57, 45, 57, 30, 23, 59, 67, 14, 16, 4, 14, 62, 15, 50, 7, 70, 64, 6, 42, 48, 9, 31, 19, 40, 49, 2, 25, 3, 41, 49, 36, 9, 29, 39, 31, 5, 17, 1, 29, 25, 11, 21, 18, 2, 8, 22, 39, 15, 8, 22, 13, 3, 19, 4, 21, 62, 34, 43, 6, 24, 17, 60, 8, 74, 6, 44, 60, 10, 33, 12, 26, 24, 45, 81, 69, 80, 41, 28, 23, 5, 10, 20, 52, 18, 13, 86, 3, 7, 59, 21, 65, 72, 34, 37, 26, 55, 47, 48, 34, 5, 44, 47, 68, 96, 82, 111, 61, 74, 30, 17, 55, 98, 81, 66, 89, 35, 74, 82, 91, 51, 55, 51, 30, 89, 61, 75, 40, 71, 73, 11, 56, 54, 19, 47, 94, 69, 64, 20, 64, 12, 54, 77, 42, 88, 36, 52, 90, 63, 70, 27, 32, 73, 91, 32, 56, 46, 9, 78, 51, 68, 88, 67, 20, 43, 40, 14, 66, 86, 39, 97, 38, 27, 50, 84, 54, 92, 61, 46, 67, 24, 58, 35, 58, 37, 98, 85, 73, 84, 48, 35, 57, 16, 26, 37, 65, 32, 72, 95, 107, 33, 77, 33, 85, 105, 106, 75, 56, 71, 79, 59, 52, 105, 79, 90, 93, 100, 88, 112, 86, 80, 65, 42, 106, 100, 93, 94, 99, 97, 93, 101, 111, 99, 83, 53, 85, 95, 108, 107, 41, 109, 84, 78, 104, 101, 69, 110, 98, 103, 80, 83, 77, 71, 76, 78, 87, 102, 104, 95, 96, 83, 87, 50, 110, 103, 112, 45, 58, 70, 94, 91, 89, 81, 101, 82, 63, 72, 100, 97, 76, 112, 53, 105, 49, 75, 109, 102, 66, 111, 68, 87, 92, 79, 96, 43, 90, 44, 110, 99, 102, 92, 103, 106, 62, 53, 27, 46, 108, 104, 107, 108, 109, 76
};
double HRA_112_112_H_cols[] = {
7, 8, 52, 12, 12, 42, 16, 69, 45, 14, 19, 23, 6, 32, 3, 5, 22, 2, 45, 50, 2, 1, 18, 84, 10, 7, 62, 11, 9, 21, 24, 63, 2, 5, 28, 13, 6, 15, 58, 39, 39, 22, 76, 13, 26, 68, 9, 10, 49, 38, 32, 11, 34, 44, 8, 7, 25, 67, 1, 17, 19, 36, 4, 41, 3, 26, 31, 15, 45, 40, 8, 4, 41, 20, 6, 53, 1, 42, 9, 20, 25, 17, 33, 41, 3, 19, 55, 17, 27, 14, 31, 88, 15, 26, 36, 16, 28, 24, 27, 16, 30, 56, 48, 43, 4, 5, 38, 37, 40, 46, 18, 18, 22, 50, 76, 34, 60, 83, 39, 73, 56, 92, 42, 52, 75, 35, 37, 33, 61, 67, 47, 75, 66, 70, 29, 92, 51, 95, 84, 21, 57, 28, 46, 66, 93, 11, 94, 55, 96, 20, 71, 48, 53, 43, 82, 90, 66, 90, 14, 44, 54, 62, 34, 58, 81, 53, 23, 43, 27, 93, 10, 86, 37, 80, 60, 49, 21, 79, 74, 72, 48, 61, 40, 76, 64, 29, 38, 79, 51, 54, 13, 49, 72, 30, 50, 86, 35, 80, 61, 56, 36, 59, 65, 91, 25, 47, 58, 59, 78, 47, 32, 24, 44, 86, 64, 57, 12, 23, 109, 107, 85, 63, 31, 65, 62, 68, 111, 78, 104, 89, 112, 87, 69, 105, 65, 94, 109, 78, 72, 104, 85, 108, 77, 106, 79, 74, 103, 96, 64, 105, 105, 102, 63, 35, 59, 108, 112, 81, 102, 57, 106, 83, 81, 77, 101, 55, 94, 96, 97, 106, 46, 101, 83, 85, 71, 107, 104, 87, 33, 67, 103, 95, 30, 91, 89, 103, 75, 51, 107, 87, 91, 89, 99, 68, 52, 109, 99, 88, 84, 112, 54, 70, 92, 100, 98, 74, 60, 100, 98, 110, 90, 73, 71, 95, 70, 100, 29, 69, 110, 93, 82, 97, 98, 77, 73, 99, 101, 108, 82, 102, 111, 110, 111, 97, 88, 80
};
double HRA_112_112_input[] = {
-5.7868467875518395, -6.340739523388657, 3.6654768375589399, 4.1452438183910827, -4.6746135252043111, -4.8353634065473701, -6.0729133999971285, 4.0335561282226271, -6.1114855315699135, 4.1029513876344916, -4.6481634503883624, 5.7650915278538646, 6.5567610490570312, 5.1810523550761207, 3.4789051916752669, 4.2678848515507122, 4.0314705275547089, 6.0297078342283799, 4.9101169653222163, -6.4577297598332324, -7.4273487270443095, 3.472130985267488, -6.5346233967202254, 7.5312028458762414, -5.2618748211985915, 6.4198074556254969, 3.7500207659511484, 5.4040878141701141, 5.7554260586578803, 3.3973620625026886, 7.1815269888532907, 5.0031747952824963, 5.1377243276145599, 5.385229914081755, -0.61384230253605643, 0.46954911161835722, 3.5182611493679663, 3.393698829567279, 6.147483866535171, 3.8374563885989228, 1.3663773773557015, -4.0917661778352352, -3.2968298202652835, -6.0371912041431148, -8.4279246895331781, -0.98556788606912304, -3.515442879601625, 4.2642476942514875, -5.5905016743156972, 3.6920101668161727, -4.035860013856472, 5.3290190966269995, -2.9729656070594057, -2.5054371041338537, 6.8683150013190115, -7.1109038108500098, 6.7301890172695158, 2.5782062882356374, 4.4161464916633282, 2.2692851122935322, -1.3682527221025034, 3.0794629981237631, -7.8655412763279973, 1.1479897597156494, 0.22370696314520414, 1.1222453403894148, -3.1335220808128219, -3.8352985265277089, -1.2463521619727009, 2.9511814015293218, -8.668811041413111, 3.0185610517830548, -6.9592962351476091, 3.9653416636625414, -3.9384322074229408, 1.6789027505247516, 2.9579632055145502, -2.1212672699995125, -3.8892168640945193, 7.516114544807583, -0.84285604179011253, 4.1295390817792512, 0.26093278495228162, -3.6071666499996047, -0.065323173773821908, -1.9146584862100915, 4.7951161310834367, 5.5440002982088803, 3.5917539980319364, -0.81416023563684481, -2.6588977758747721, -3.0404494660606227, 4.5389936536649662, 2.7870543501114082, 3.5622966707453889, 5.1982116994791161, 2.4775319712999302, 0.70541080068007755, 0.89622787904518464, 4.3789020039207758, -2.4976040580619445, -0.7201255450933205, 4.2071986295109394, -5.2418379271657001, -4.092365654835163, -4.3510198326542557, 3.7404138637596001, 1.2496890930262492, -7.1053909336149728, -4.8888279905256748, -6.3523901926735249, -1.8757980409249277, 3.6256343910366273, -3.6165398844758228, -0.38322352317510561, -0.84747550047769449, -1.2717892264620718, -2.3899810721111154, 4.1368500898628637, 3.0440159002314924, 3.4235543074310728, -2.146097053557551, -1.7537615307751735, -1.0280987119225686, 4.9009275359419204, 5.0046047156368116, -0.47700833783807428, -4.5989492891875567, 1.4154839158712684, 0.33410724822249849, -4.771937854508927, -1.1817007924012972, -2.5960865023249302, 0.30422629502493687, -2.2097849377516763, -4.343244940878872, 1.9464288912612249, -9.0976989032526809, -8.6454142547592685, -1.8164317522989997, 2.2780845702169961, -4.8775405042023356, -0.61834757216625769, -1.985554501661331, -0.87599558657596699, -8.0610201531782124, -5.9847574894882554, -10.365536404711067, 2.9782191161319376, -6.9443820217795169, 0.72935566343949876, -4.5326632961380664, 1.1307250622386897, -4.0853969692041314, 5.4926924507347596, 5.6722555096362042, -2.5069992226180222, 2.0460084066662092, 2.5375899018238197, -3.5264293517823679, 3.2103083878487557, 5.793713046583183, -2.7633653287377995, 6.482851815629938, -1.2471646528152021, 3.0010491047486085, 0.29072399293868856, -4.0686659405747738, -2.6253508133431289, -6.3896590677017171, 5.7054076607727886, 4.3053292399977092, 2.2372599539047151, -4.8975607398431897, 5.8124794005531406, -0.69648233429781359, 5.5509723605410004, 2.0900652762982923, -4.7944253330785118, -2.9224693872108287, 6.0218579796888303, 4.7027436964063387, -4.1564871824868659, -1.324779121305123, 0.38031612697724176, -0.69335927945709175, -0.4028295686263082, 2.0967669774299189, 2.7947186736855909, 2.1473880039026203, 6.368702510367898, -3.0691782325684049, 1.6125827087903837, 3.5925359669662518, 5.178224480471127, -2.5070763799556617, 4.4280512389456632, -6.5385259627250134, 2.8047951999607603, -3.0185715385981151, -0.33348983718789993, -4.3285127692183556, -7.9609407359365134, 7.064973172264966, 0.95714371675898213, -5.5481272272415545, -1.6024149180708045, -4.5740915350065992, -1.5117120929647263, 1.9996824689403947, 5.9527526663437724, 5.0239857792804967, 6.2677418491798784, -1.9758548902654505, 2.1709284879472324, 2.5054563138111572, 4.4483685492445115, 3.2098357106645676, -4.5306213859481099, 1.1291114493451548, 1.5827945023160555, -5.2733490015732292, 5.0664709821503457, 1.9652801880230106
};
char HRA_112_112_detected_data[] = {
1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0
};
+164
View File
@@ -0,0 +1,164 @@
/*
Copyright (c) 2003-2010, Mark Borgerding
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* kiss_fft.h
defines kiss_fft_scalar as either short or a float type
and defines
typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
#include "kiss_fft.h"
#include <limits.h>
#define MAXFACTORS 32
/* e.g. an fft of length 128 has 4 factors
as far as kissfft is concerned
4*4*4*2
*/
struct kiss_fft_state{
int nfft;
int inverse;
int factors[2*MAXFACTORS];
kiss_fft_cpx twiddles[1];
};
/*
Explanation of macros dealing with complex math:
C_MUL(m,a,b) : m = a*b
C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise
C_SUB( res, a,b) : res = a - b
C_SUBFROM( res , a) : res -= a
C_ADDTO( res , a) : res += a
* */
#ifdef FIXED_POINT
#if (FIXED_POINT==32)
# define FRACBITS 31
# define SAMPPROD int64_t
#define SAMP_MAX 2147483647
#else
# define FRACBITS 15
# define SAMPPROD int32_t
#define SAMP_MAX 32767
#endif
#define SAMP_MIN -SAMP_MAX
#if defined(CHECK_OVERFLOW)
# define CHECK_OVERFLOW_OP(a,op,b) \
if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \
fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); }
#endif
# define smul(a,b) ( (SAMPPROD)(a)*(b) )
# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS )
# define S_MUL(a,b) sround( smul(a,b) )
# define C_MUL(m,a,b) \
do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \
(m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0)
# define DIVSCALAR(x,k) \
(x) = sround( smul( x, SAMP_MAX/k ) )
# define C_FIXDIV(c,div) \
do { DIVSCALAR( (c).r , div); \
DIVSCALAR( (c).i , div); }while (0)
# define C_MULBYSCALAR( c, s ) \
do{ (c).r = sround( smul( (c).r , s ) ) ;\
(c).i = sround( smul( (c).i , s ) ) ; }while(0)
#else /* not FIXED_POINT*/
# define S_MUL(a,b) ( (a)*(b) )
#define C_MUL(m,a,b) \
do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
(m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
# define C_FIXDIV(c,div) /* NOOP */
# define C_MULBYSCALAR( c, s ) \
do{ (c).r *= (s);\
(c).i *= (s); }while(0)
#endif
#ifndef CHECK_OVERFLOW_OP
# define CHECK_OVERFLOW_OP(a,op,b) /* noop */
#endif
#define C_ADD( res, a,b)\
do { \
CHECK_OVERFLOW_OP((a).r,+,(b).r)\
CHECK_OVERFLOW_OP((a).i,+,(b).i)\
(res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \
}while(0)
#define C_SUB( res, a,b)\
do { \
CHECK_OVERFLOW_OP((a).r,-,(b).r)\
CHECK_OVERFLOW_OP((a).i,-,(b).i)\
(res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \
}while(0)
#define C_ADDTO( res , a)\
do { \
CHECK_OVERFLOW_OP((res).r,+,(a).r)\
CHECK_OVERFLOW_OP((res).i,+,(a).i)\
(res).r += (a).r; (res).i += (a).i;\
}while(0)
#define C_SUBFROM( res , a)\
do {\
CHECK_OVERFLOW_OP((res).r,-,(a).r)\
CHECK_OVERFLOW_OP((res).i,-,(a).i)\
(res).r -= (a).r; (res).i -= (a).i; \
}while(0)
#ifdef FIXED_POINT
# define KISS_FFT_COS(phase) floorf(.5+SAMP_MAX * cosf (phase))
# define KISS_FFT_SIN(phase) floorf(.5+SAMP_MAX * sinf (phase))
# define HALF_OF(x) ((x)>>1)
#elif defined(USE_SIMD)
# define KISS_FFT_COS(phase) _mm_set1_ps( cosf(phase) )
# define KISS_FFT_SIN(phase) _mm_set1_ps( sinf(phase) )
# define HALF_OF(x) ((x)*_mm_set1_ps(.5))
#else
# define KISS_FFT_COS(phase) (kiss_fft_scalar) cosf(phase)
# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sinf(phase)
# define HALF_OF(x) ((x)*.5)
#endif
#define kf_cexp(x,phase) \
do{ \
(x)->r = KISS_FFT_COS(phase);\
(x)->i = KISS_FFT_SIN(phase);\
}while(0)
/* a debugging function */
#define pcpx(c)\
fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) )
#ifdef KISS_FFT_USE_ALLOCA
// define this to allow use of alloca instead of malloc for temporary buffers
// Temporary buffers are used in two case:
// 1. FFT sizes that have "bad" factors. i.e. not 2,3 and 5
// 2. "in-place" FFTs. Notice the quotes, since kissfft does not really do an in-place transform.
#include <alloca.h>
#define KISS_FFT_TMP_ALLOC(nbytes) alloca(nbytes)
#define KISS_FFT_TMP_FREE(ptr)
#else
#define KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes)
#define KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr)
#endif
+39
View File
@@ -0,0 +1,39 @@
/*---------------------------------------------------------------------------*\
FILE........: ampexp.h
AUTHOR......: David Rowe
DATE CREATED: & August 2012
Functions for experimenting with amplitude quantisation.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2012 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not,see <http://www.gnu.org/licenses/>.
*/
#ifndef __AMPEX__
#define __AMPEXP__
#include "defines.h"
struct AEXP;
struct AEXP *amp_experiment_create();
void amp_experiment_destroy(struct AEXP *aexp);
void amp_experiment(struct AEXP *aexp, MODEL *model, char *arg);
#endif
+106
View File
@@ -0,0 +1,106 @@
#define BPF_N 101
float bpf[]={
0.002174,
0.003245,
0.002147,
0.001866,
0.002764,
0.000567,
-0.001641,
-0.000565,
-0.002415,
-0.005837,
-0.003620,
-0.002828,
-0.006268,
-0.002787,
0.001963,
-0.001234,
0.001446,
0.009200,
0.005331,
0.003521,
0.011821,
0.006951,
-0.002015,
0.005137,
0.001828,
-0.013390,
-0.007058,
-0.003273,
-0.020458,
-0.014321,
0.001751,
-0.012891,
-0.009730,
0.018993,
0.008544,
0.000534,
0.035755,
0.029074,
-0.001192,
0.030852,
0.030983,
-0.029834,
-0.009550,
0.011945,
-0.081971,
-0.082875,
0.000423,
-0.133526,
-0.211778,
0.182628,
0.514906,
0.182628,
-0.211778,
-0.133526,
0.000423,
-0.082875,
-0.081971,
0.011945,
-0.009550,
-0.029834,
0.030983,
0.030852,
-0.001192,
0.029074,
0.035755,
0.000534,
0.008544,
0.018993,
-0.009730,
-0.012891,
0.001751,
-0.014321,
-0.020458,
-0.003273,
-0.007058,
-0.013390,
0.001828,
0.005137,
-0.002015,
0.006951,
0.011821,
0.003521,
0.005331,
0.009200,
0.001446,
-0.001234,
0.001963,
-0.002787,
-0.006268,
-0.002828,
-0.003620,
-0.005837,
-0.002415,
-0.000565,
-0.001641,
0.000567,
0.002764,
0.001866,
0.002147,
0.003245,
0.002174
};
+105
View File
@@ -0,0 +1,105 @@
#define BPFB_N 101
float bpfb[]={
0.003795,
0.006827,
0.002261,
0.002523,
0.005758,
-0.000264,
-0.000674,
0.003113,
-0.004144,
-0.004923,
0.000043,
-0.008017,
-0.008711,
-0.001802,
-0.010210,
-0.010428,
-0.000899,
-0.009413,
-0.009072,
0.003469,
-0.005335,
-0.004828,
0.010724,
0.000941,
0.000708,
0.018957,
0.007084,
0.004825,
0.025418,
0.010147,
0.004452,
0.027434,
0.007550,
-0.002861,
0.023483,
-0.001944,
-0.018138,
0.014122,
-0.017583,
-0.040768,
0.002598,
-0.036604,
-0.069541,
-0.004273,
-0.054876,
-0.107289,
0.010068,
-0.068052,
-0.200119,
0.207287,
0.597150,
0.207287,
-0.200119,
-0.068052,
0.010068,
-0.107289,
-0.054876,
-0.004273,
-0.069541,
-0.036604,
0.002598,
-0.040768,
-0.017583,
0.014122,
-0.018138,
-0.001944,
0.023483,
-0.002861,
0.007550,
0.027434,
0.004452,
0.010147,
0.025418,
0.004825,
0.007084,
0.018957,
0.000708,
0.000941,
0.010724,
-0.004828,
-0.005335,
0.003469,
-0.009072,
-0.009413,
-0.000899,
-0.010428,
-0.010210,
-0.001802,
-0.008711,
-0.008017,
0.000043,
-0.004923,
-0.004144,
0.003113,
-0.000674,
-0.000264,
0.005758,
0.002523,
0.002261,
0.006827,
0.003795
};
+245
View File
@@ -0,0 +1,245 @@
/* THIS IS A GENERATED FILE. Edit generate_codebook.c and its input */
/*
* This intermediary file and the files that used to create it are under
* The LGPL. See the file COPYING.
*/
#include "defines.h"
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp1.txt */
static const float codes0[] = {
225,
250,
275,
300,
325,
350,
375,
400,
425,
450,
475,
500,
525,
550,
575,
600
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp2.txt */
static const float codes1[] = {
325,
350,
375,
400,
425,
450,
475,
500,
525,
550,
575,
600,
625,
650,
675,
700
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp3.txt */
static const float codes2[] = {
500,
550,
600,
650,
700,
750,
800,
850,
900,
950,
1000,
1050,
1100,
1150,
1200,
1250
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp4.txt */
static const float codes3[] = {
700,
800,
900,
1000,
1100,
1200,
1300,
1400,
1500,
1600,
1700,
1800,
1900,
2000,
2100,
2200
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp5.txt */
static const float codes4[] = {
950,
1050,
1150,
1250,
1350,
1450,
1550,
1650,
1750,
1850,
1950,
2050,
2150,
2250,
2350,
2450
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp6.txt */
static const float codes5[] = {
1100,
1200,
1300,
1400,
1500,
1600,
1700,
1800,
1900,
2000,
2100,
2200,
2300,
2400,
2500,
2600
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp7.txt */
static const float codes6[] = {
1500,
1600,
1700,
1800,
1900,
2000,
2100,
2200,
2300,
2400,
2500,
2600,
2700,
2800,
2900,
3000
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp8.txt */
static const float codes7[] = {
2300,
2400,
2500,
2600,
2700,
2800,
2900,
3000
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp9.txt */
static const float codes8[] = {
2500,
2600,
2700,
2800,
2900,
3000,
3100,
3200
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp10.txt */
static const float codes9[] = {
2900,
3100,
3300,
3500
};
const struct lsp_codebook lsp_cb[] = {
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp1.txt */
{
1,
4,
16,
codes0
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp2.txt */
{
1,
4,
16,
codes1
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp3.txt */
{
1,
4,
16,
codes2
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp4.txt */
{
1,
4,
16,
codes3
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp5.txt */
{
1,
4,
16,
codes4
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp6.txt */
{
1,
4,
16,
codes5
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp7.txt */
{
1,
4,
16,
codes6
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp8.txt */
{
1,
3,
8,
codes7
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp9.txt */
{
1,
3,
8,
codes8
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lsp10.txt */
{
1,
2,
4,
codes9
},
{ 0, 0, 0, 0 }
};
+433
View File
@@ -0,0 +1,433 @@
/* THIS IS A GENERATED FILE. Edit generate_codebook.c and its input */
/*
* This intermediary file and the files that used to create it are under
* The LGPL. See the file COPYING.
*/
#include "defines.h"
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp1.txt */
static const float codes0[] = {
25,
50,
75,
100,
125,
150,
175,
200,
225,
250,
275,
300,
325,
350,
375,
400,
425,
450,
475,
500,
525,
550,
575,
600,
625,
650,
675,
700,
725,
750,
775,
800
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp2.txt */
static const float codes1[] = {
25,
50,
75,
100,
125,
150,
175,
200,
225,
250,
275,
300,
325,
350,
375,
400,
425,
450,
475,
500,
525,
550,
575,
600,
625,
650,
675,
700,
725,
750,
775,
800
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp3.txt */
static const float codes2[] = {
25,
50,
75,
100,
125,
150,
175,
200,
225,
250,
275,
300,
325,
350,
375,
400,
425,
450,
475,
500,
525,
550,
575,
600,
625,
650,
675,
700,
725,
750,
775,
800
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp4.txt */
static const float codes3[] = {
25,
50,
75,
100,
125,
150,
175,
200,
250,
300,
350,
400,
450,
500,
550,
600,
650,
700,
750,
800,
850,
900,
950,
1000,
1050,
1100,
1150,
1200,
1250,
1300,
1350,
1400
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp5.txt */
static const float codes4[] = {
25,
50,
75,
100,
125,
150,
175,
200,
250,
300,
350,
400,
450,
500,
550,
600,
650,
700,
750,
800,
850,
900,
950,
1000,
1050,
1100,
1150,
1200,
1250,
1300,
1350,
1400
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp6.txt */
static const float codes5[] = {
25,
50,
75,
100,
125,
150,
175,
200,
250,
300,
350,
400,
450,
500,
550,
600,
650,
700,
750,
800,
850,
900,
950,
1000,
1050,
1100,
1150,
1200,
1250,
1300,
1350,
1400
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp7.txt */
static const float codes6[] = {
25,
50,
75,
100,
125,
150,
175,
200,
225,
250,
275,
300,
325,
350,
375,
400,
425,
450,
475,
500,
525,
550,
575,
600,
625,
650,
675,
700,
725,
750,
775,
800
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp8.txt */
static const float codes7[] = {
25,
50,
75,
100,
125,
150,
175,
200,
225,
250,
275,
300,
325,
350,
375,
400,
425,
450,
475,
500,
525,
550,
575,
600,
625,
650,
675,
700,
725,
750,
775,
800
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp9.txt */
static const float codes8[] = {
25,
50,
75,
100,
125,
150,
175,
200,
225,
250,
275,
300,
325,
350,
375,
400,
425,
450,
475,
500,
525,
550,
575,
600,
625,
650,
675,
700,
725,
750,
775,
800
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp10.txt */
static const float codes9[] = {
25,
50,
75,
100,
125,
150,
175,
200,
225,
250,
275,
300,
325,
350,
375,
400,
425,
450,
475,
500,
525,
550,
575,
600,
625,
650,
675,
700,
725,
750,
775,
800
};
const struct lsp_codebook lsp_cbd[] = {
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp1.txt */
{
1,
5,
32,
codes0
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp2.txt */
{
1,
5,
32,
codes1
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp3.txt */
{
1,
5,
32,
codes2
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp4.txt */
{
1,
5,
32,
codes3
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp5.txt */
{
1,
5,
32,
codes4
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp6.txt */
{
1,
5,
32,
codes5
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp7.txt */
{
1,
5,
32,
codes6
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp8.txt */
{
1,
5,
32,
codes7
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp9.txt */
{
1,
5,
32,
codes8
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/dlsp10.txt */
{
1,
5,
32,
codes9
},
{ 0, 0, 0, 0 }
};
+279
View File
@@ -0,0 +1,279 @@
/* THIS IS A GENERATED FILE. Edit generate_codebook.c and its input */
/*
* This intermediary file and the files that used to create it are under
* The LGPL. See the file COPYING.
*/
#include "defines.h"
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/gecb.txt */
static const float codes0[] = {
2.71, 12.0184,
0.04675, -2.73881,
0.120993, 8.38895,
-1.58028, -0.892307,
1.19307, -1.91561,
0.187101, -3.27679,
0.332251, -7.66455,
-1.47944, 31.2461,
1.52761, 27.7095,
-0.524379, 5.25012,
0.55333, 7.4388,
-0.843451, -1.95299,
2.26389, 8.61029,
0.143143, 2.36549,
0.616506, 1.28427,
-1.71133, 22.0967,
1.00813, 17.3965,
-0.106718, 1.41891,
-0.136246, 14.2736,
-1.70909, -20.5319,
1.65787, -3.39107,
0.138049, -4.95785,
0.536729, -1.94375,
0.196307, 36.8519,
1.27248, 22.5565,
-0.670219, -1.90604,
0.382092, 6.40113,
-0.756911, -4.90102,
1.82931, 4.6138,
0.318794, 0.73683,
0.612815, -2.07505,
-0.410151, 24.7871,
1.77602, 13.1909,
0.106457, -0.104492,
0.192206, 10.1838,
-1.82442, -7.71565,
0.931346, 4.34835,
0.308813, -4.086,
0.397143, -11.8089,
-0.048715, 41.2273,
0.877342, 35.8503,
-0.759794, 0.476634,
0.978593, 7.67467,
-1.19506, 3.03883,
2.63989, -3.41106,
0.191127, 3.60351,
0.402932, 1.0843,
-2.15202, 18.1076,
1.5468, 8.32271,
-0.143089, -4.07592,
-0.150142, 5.86674,
-1.40844, -3.2507,
1.56615, -10.4132,
0.178171, -10.2267,
0.362164, -0.028556,
-0.070125, 24.3907,
0.594752, 17.4828,
-0.28698, -6.90407,
0.464818, 10.2055,
-1.00684, -14.3572,
2.32957, -3.69161,
0.335745, 2.40714,
1.01966, -3.15565,
-1.25945, 7.9919,
2.38369, 19.6806,
-0.094947, -2.41374,
0.20933, 6.66477,
-2.22103, 1.37986,
1.29239, 2.04633,
0.243626, -0.890741,
0.428773, -7.19366,
-1.11374, 41.3414,
2.6098, 31.1405,
-0.446468, 2.53419,
0.490104, 4.62757,
-1.11723, -3.24174,
1.79156, 8.41493,
0.156012, 0.183336,
0.532447, 3.15455,
-0.764484, 18.514,
0.952395, 11.7713,
-0.332567, 0.346987,
0.202165, 14.7168,
-2.12924, -15.559,
1.35358, -1.92679,
-0.010963, -16.3364,
0.399053, -2.79057,
0.750657, 31.1483,
0.655743, 24.4819,
-0.45321, -0.735879,
0.2869, 6.5467,
-0.715673, -12.3578,
1.54849, 3.87217,
0.271874, 0.802339,
0.502073, -4.85485,
-0.497037, 17.7619,
1.19116, 13.9544,
0.01563, 1.33157,
0.341867, 8.93537,
-2.31601, -5.39506,
0.75861, 1.9645,
0.24132, -3.23769,
0.267151, -11.2344,
-0.273126, 32.6248,
1.75352, 40.432,
-0.784011, 3.04576,
0.705987, 5.66118,
-1.3864, 1.35356,
2.37646, 1.67485,
0.242973, 4.73218,
0.491227, 0.354061,
-1.60676, 8.65895,
1.16711, 5.9871,
-0.137601, -12.0417,
-0.251375, 10.3972,
-1.43151, -8.90411,
0.98828, -13.209,
0.261484, -6.35497,
0.395932, -0.702529,
0.283704, 26.8996,
0.420959, 15.4418,
-0.355804, -13.7278,
0.527372, 12.3985,
-1.16956, -15.9985,
1.90669, -5.81605,
0.354492, 3.85157,
0.82576, -4.16264,
-0.49019, 13.0572,
2.25577, 13.5264,
-0.004956, -3.23713,
0.026709, 7.86645,
-1.81037, -0.451183,
1.08383, -0.18362,
0.135836, -2.26658,
0.375812, -5.51225,
-1.96644, 38.6829,
1.97799, 24.5655,
-0.704656, 6.35881,
0.480786, 7.05175,
-0.976417, -2.42273,
2.50215, 6.75935,
0.083588, 3.2588,
0.543629, 0.910013,
-1.23196, 23.0915,
0.785492, 14.807,
-0.213554, 1.688,
0.004748, 18.1718,
-1.54719, -16.1168,
1.50104, -3.28114,
0.080133, -4.63472,
0.476592, -2.18093,
0.44247, 40.304,
1.07277, 27.592,
-0.594738, -4.16681,
0.42248, 7.61609,
-0.927521, -7.27441,
1.99162, 1.29636,
0.291307, 2.39878,
0.721081, -1.95062,
-0.804256, 24.9295,
1.64839, 19.1197,
0.060852, -0.590639,
0.266085, 9.10325,
-1.9574, -2.88461,
1.11693, 2.6724,
0.35458, -2.74854,
0.330733, -14.1561,
-0.527851, 39.5756,
0.991152, 43.195,
-0.589619, 1.26919,
0.787401, 8.73071,
-1.0138, 1.02507,
2.8254, 1.89538,
0.24089, 2.74557,
0.427195, 2.54446,
-1.95311, 12.244,
1.44862, 12.0607,
-0.210492, -3.37906,
-0.056713, 10.204,
-1.65237, -5.10274,
1.29475, -12.2708,
0.111608, -8.67592,
0.326634, -1.16763,
0.021781, 31.1258,
0.455335, 21.4684,
-0.37544, -3.37121,
0.39362, 11.302,
-0.851456, -19.4149,
2.10703, -2.22886,
0.373233, 1.92406,
0.884438, -1.72058,
-0.975127, 9.84013,
2.0033, 17.3954,
-0.036915, -1.11137,
0.148456, 5.39997,
-1.91441, 4.77382,
1.44791, 0.537122,
0.194979, -1.03818,
0.495771, -9.95502,
-1.05899, 32.9471,
2.01122, 32.4544,
-0.30965, 4.71911,
0.436082, 4.63552,
-1.23711, -1.25428,
2.02274, 9.42834,
0.190342, 1.46077,
0.479017, 2.48479,
-1.07848, 16.2217,
1.20764, 9.65421,
-0.258087, -1.67236,
0.071852, 13.416,
-1.87723, -16.072,
1.28957, -4.87118,
0.067713, -13.4427,
0.435551, -4.1655,
0.46614, 30.5895,
0.904895, 21.598,
-0.518369, -2.53205,
0.337363, 5.63726,
-0.554975, -17.4005,
1.69188, 1.14574,
0.227934, 0.889297,
0.587303, -5.72973,
-0.262133, 18.6666,
1.39505, 17.0029,
-0.01909, 4.30838,
0.304235, 12.6699,
-2.07406, -6.46084,
0.920546, 1.21296,
0.284927, -1.78547,
0.209724, -16.024,
-0.636067, 31.5768,
1.34989, 34.6775,
-0.971625, 5.30086,
0.590249, 4.44971,
-1.56787, 3.60239,
2.1455, 4.51666,
0.296022, 4.12017,
0.445299, 0.868772,
-1.44193, 14.1284,
1.35575, 6.0074,
-0.012814, -7.49657,
-0.43, 8.50012,
-1.20469, -7.11326,
1.10102, -6.83682,
0.196463, -6.234,
0.436747, -1.12979,
0.141052, 22.8549,
0.290821, 18.8114,
-0.529536, -7.73251,
0.63428, 10.7898,
-1.33472, -20.3258,
1.81564, -1.90332,
0.394778, 3.79758,
0.732682, -8.18382,
-0.741244, 11.7683
};
const struct lsp_codebook ge_cb[] = {
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/gecb.txt */
{
2,
8,
256,
codes0
},
{ 0, 0, 0, 0 }
};
File diff suppressed because it is too large Load Diff
+235
View File
@@ -0,0 +1,235 @@
/* THIS IS A GENERATED FILE. Edit generate_codebook.c and its input */
/*
* This intermediary file and the files that used to create it are under
* The LGPL. See the file COPYING.
*/
#include "defines.h"
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lspmelvq1.txt */
static const float codes0[] = {
640.185, 893.139, 1393.85, 1494.06, 1656.26, 1700.82,
558.516, 716.906, 1057.36, 1182.62, 1503.8, 1610.03,
615.108, 769.622, 1120.16, 1222.84, 1366.46, 1465.05,
663.458, 736.833, 964.764, 1043.54, 1623.17, 1681.29,
487.957, 577.723, 1017.43, 1177.04, 1552.1, 1615.69,
536.099, 733.407, 1292.28, 1406.09, 1577.7, 1637.49,
473.015, 542.559, 877.397, 1285.82, 1591.04, 1647.44,
525.343, 652.014, 1206.83, 1493.96, 1647.97, 1698.3,
510.887, 572.868, 945.226, 1445.68, 1678.17, 1705.53,
534.915, 721.265, 1275.92, 1415.76, 1648.5, 1695.73,
865.189, 1047, 1267.14, 1389.32, 1646.57, 1696.97,
608.033, 869.887, 1300.95, 1432.87, 1639.74, 1689.41,
554.972, 649.352, 866.845, 979.873, 1645.31, 1695.39,
696.079, 813.97, 1102.49, 1219.79, 1536.49, 1621.94,
553.879, 691.097, 1200.84, 1339.34, 1629.08, 1683.5,
778.561, 997.776, 1258.63, 1390.34, 1601.99, 1657.86,
713.107, 778.893, 992.875, 1051.95, 1497.45, 1650.66,
490.27, 598.18, 1116.02, 1244.13, 1622.26, 1672.21,
448.556, 512.085, 1271.7, 1448.18, 1579.37, 1642.48,
465.688, 535.312, 1099.19, 1535.79, 1684.29, 1710.9,
812.222, 1087.53, 1470.44, 1559.73, 1692.18, 1726.38,
428.174, 489.426, 1160.33, 1409.3, 1597.5, 1651.3,
712.81, 957.56, 1433.02, 1516.37, 1675.39, 1710.06,
717.255, 934.073, 1305.2, 1436.72, 1647.2, 1693.09,
492.888, 580.393, 1339.52, 1461.07, 1592, 1653.42,
550.467, 675.888, 990.888, 1177.44, 1615.64, 1658,
714.528, 801.792, 1072.94, 1146.08, 1637.06, 1706.58,
513.819, 590.989, 798.691, 895.755, 1557.76, 1624.56,
436.653, 518.413, 1281.99, 1547.08, 1685.12, 1717.76,
681.854, 758.354, 1046.65, 1120.92, 1412.25, 1603.42,
873.962, 1118.49, 1376.61, 1465.07, 1665.38, 1707.18,
553.529, 634.092, 1144.77, 1284.8, 1542.87, 1620.63,
448.532, 519.097, 1054.57, 1319.66, 1591.26, 1649.85,
742.267, 885.293, 1152.83, 1318.51, 1569.36, 1631.45,
529.03, 654.522, 1355.76, 1511.75, 1662.39, 1706.4,
463.794, 597.77, 1176.05, 1366.13, 1629.37, 1678.01,
626.936, 706.66, 1058.04, 1323.62, 1473.28, 1599.68,
477.322, 615.5, 1488.89, 1550.5, 1683.1, 1712.34,
547.442, 815.442, 1313.38, 1486.96, 1671.97, 1717.4,
610.671, 819.955, 1219.11, 1363.66, 1592.05, 1654.31,
547.414, 746.54, 1438.43, 1517.72, 1659.64, 1695.57,
604.823, 821.146, 1137.94, 1358.29, 1598.94, 1655.64,
525.935, 616.739, 1060.13, 1427.33, 1593.35, 1657.48,
622.5, 762.143, 1318.65, 1410.96, 1618.12, 1680.06,
436.917, 516.583, 1390.29, 1475.86, 1594.71, 1633.74,
792.487, 1031.24, 1362.62, 1472.68, 1649.26, 1697.35,
457.707, 526.207, 865.966, 1120.47, 1564.83, 1625.28,
526.39, 624.21, 1269.65, 1374.23, 1558.07, 1620.96,
483.768, 573.505, 1440.66, 1512.43, 1622.37, 1671.31,
953.061, 1194.03, 1416.67, 1515.82, 1678.82, 1718.21,
499.947, 627.358, 1299.94, 1394.23, 1643.17, 1685.33,
648.723, 838.181, 1225.5, 1383.45, 1637.46, 1691.67,
672.588, 1022.6, 1346.21, 1443.75, 1651.15, 1695.43,
581.833, 674.944, 955.167, 1020.5, 1370.5, 1503.11,
536.143, 652.531, 1243.84, 1315.27, 1425.1, 1505.73,
560.558, 786.65, 1224.66, 1373.98, 1630.06, 1682.68,
591.926, 783.722, 982, 1140.81, 1581.61, 1625.28,
548.537, 644.524, 940.451, 1048.74, 1557.89, 1609.48,
516.916, 723.253, 1135.95, 1309.19, 1600.08, 1669.48,
426.521, 506.077, 1457.73, 1535.02, 1641.35, 1678.45,
645.189, 776.595, 1020.78, 1240.07, 1597, 1648.7,
637.105, 941.474, 1242.21, 1372.49, 1646.7, 1694.8,
691.228, 788.141, 1202.12, 1294.89, 1626.97, 1681.77,
699.08, 886.655, 1300.9, 1399.28, 1579.94, 1646.79
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lspmelvq2.txt */
static const float codes1[] = {
4.44342, 51.1708, 7.45726, -27.4373, -18.5056, -18.1989,
51.58, 63.3166, 57.7796, -44.1591, -18.4834, -6.93392,
-20.2795, -21.7454, 4.66947, 52.1569, 30.4367, 36.8582,
-29.1104, -5.63933, -3.45383, -63.0261, -20.4423, -19.0485,
2.91622, 40.8374, 16.579, -51.8461, 38.5045, 18.1728,
-20.6977, -11.4022, -36.6173, -16.6116, -56.8965, -24.301,
-20.2385, 26.6332, 33.1191, 27.6284, -36.7493, -25.6041,
54.9871, 0.71748, 23.0674, -22.1031, 11.6643, 10.9938,
-62.7215, 21.7547, 21.2907, -7.64891, -4.5533, -9.71777,
-9.56338, -3.85841, 25.0454, -9.45216, 6.05017, 5.35043,
47.3823, 56.6122, -27.0315, -24.67, 4.86343, -0.225495,
26.3997, 26.7857, -1.66167, 62.8366, -19.7653, -8.55169,
-8.77648, -9.04545, -7.88996, 28.2433, -35.0963, -21.9709,
14.8423, 25.4563, -56.1262, -50.2934, -22.9393, -15.8113,
4.94186, 27.7798, 8.34579, 10.8553, -3.12587, -3.97807,
12.6426, -52.2317, 37.2487, -57.2067, -14.5125, -5.54035,
13.485, 15.3246, -23.9644, -21.3135, 19.5779, 14.1597,
-55.3543, -45.2077, 10.5185, 43.0461, -24.9859, -19.3484,
27.7226, 32.1882, 20.0321, 24.3328, -72.8194, -51.1823,
-31.3818, -5.25745, -43.7806, 14.1312, 17.6392, 9.81024,
-48.26, -26.2973, -44.1428, -31.9001, 22.5085, -0.467938,
7.37202, -7.79071, -12.5732, 27.1074, 9.34052, 14.4477,
14.5295, 8.82597, 57.0009, -16.3234, -32.4142, -21.0224,
32.4616, 48.6062, 38.5452, 9.77182, 1.82856, 11.5063,
-43.8275, -22.6263, -29.8278, 13.6115, 9.66849, -63.5218,
-11.9967, 2.74308, -73.6375, -20.9809, -4.11839, 7.71405,
24.0162, -2.29513, -6.80983, -26.4043, -21.8529, -16.3381,
-16.1484, 35.9086, -3.0837, 3.83958, 42.3003, 17.5003,
54.1225, -48.7513, -14.8712, -38.1256, 15.2903, 7.33079,
53.0929, 13.9221, 10.6536, 24.345, -16.5952, -16.0365,
33.1415, 38.5714, -26.0251, 22.021, 15.6866, 13.2593,
15.7194, -49.4061, 31.4552, 10.1896, 0.219911, 1.62902,
4.10868, 14.2755, 58.475, -1.16668, 52.6265, 43.4938,
358.653, -112.587, 85.9867, 52.08, -52.88, -249.24,
-12.5792, -6.64039, -33.0106, 1.51449, 50.3259, 61.6091,
-6.81685, 14.3146, 14.1563, 53.6363, 83.6051, 38.174,
-18.0006, 41.3575, -46.3736, 8.47794, -10.4611, -11.3847,
28.7711, 31.4689, -39.5744, 1.43977, -37.7309, -30.5309,
-34.4692, -11.0778, 44.4681, -60.0045, -44.9729, -34.8364,
38.7401, 41.0529, -7.92946, 20.0279, 74.4246, 54.6498,
81.8008, 133.531, -5.47375, 34.4759, 75.7417, 52.6112,
-61.5067, -76.6328, -47.2471, -43.5928, -9.46878, 0.832598,
-11.544, -44.7728, -13.9257, -3.32122, 24.816, 21.9064,
2.83945, -45.0522, -36.8776, -14.7577, -11.9912, -8.75366,
-8.97657, -14.0499, 39.2628, 48.8038, -14.3789, -4.79625,
31.6292, 32.0168, 5.52278, -79.8411, -24.1789, -15.7597,
15.893, 10.4667, -43.9057, -20.4885, 80.7594, 6.8023,
22.3285, -69.4942, -5.16156, 48.8868, 4.01995, -3.04376,
31.4062, -20.0952, -55.1259, 0.505988, 20.86, 15.0816,
-12.9696, 37.2548, 18.1009, 51.0767, 18.2053, 19.8474,
-45.4855, -45.3454, -4.22795, -15.8693, -6.07272, -1.99631,
-9.25462, 45.0241, 70.2879, -44.4484, 2.63165, 4.15336,
-51.1589, -27.7586, 19.7999, -9.87882, 63.4125, 48.3124,
-8.94084, -13.4815, -44.9602, 52.839, -17.2582, -1.59439,
23.18, -3.00374, 33.162, 31.5424, 29.111, 25.9327,
-28.4665, -10.6868, 88.7543, -3.88024, 17.5881, 13.7336,
-10.6578, 7.43021, -20.945, -17.6491, -11.2815, -10.8001,
-35.6182, -6.90301, 3.92829, 26.9695, 2.8894, 5.01685,
-3.78263, -19.2095, -10.5568, -67.7468, 20.3733, 29.552,
53.8109, -33.8374, -27.8223, -7.73289, -31.3462, -23.5678,
-38.8762, -17.7679, 11.457, 28.4607, 50.7006, -19.2488,
-44.6024, -60.2806, 56.35, 21.7545, 5.23677, 7.66608,
-3.80758, -39.1425, 28.8305, -3.09285, -42.7534, -25.1803,
45.2559, 28.8742, 60.0723, 64.461, 3.51203, -27.883
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lspmelvq3.txt */
static const float codes2[] = {
-9.63558, 27.5501, 15.4445, -4.34872, -1.8587, 1.27054,
-15.5343, 23.0515, -15.4436, -2.01887, -6.19433, -13.5085,
8.38867, -1.60998, -32.3903, 10.1765, 1.9467, 12.2454,
-3.06306, -9.55983, 14.367, -1.87159, 19.6192, -3.78366,
-18.495, -13.3811, -23.8928, -20.3745, -6.87856, -17.4887,
15.4925, 14.707, -0.0697855, 15.7541, 12.6051, -3.19768,
9.60466, -4.56494, 10.1616, 15.5594, 6.89224, -31.5602,
-11.5625, -23.0872, 34.9163, 12.3052, 7.67426, -1.26298,
2.5486, -3.90251, -19.1132, 7.6131, -31.0016, 12.4759,
2.74156, 12.4124, -39.5057, -0.325024, -22.9186, -28.5606,
6.30148, 15.4402, -2.6284, -20.1603, 5.22906, -12.3451,
-6.91862, 16.6335, -1.65064, 2.99602, -23.9479, -1.43947,
-14.3907, -31.417, 10.1113, 1.70013, -21.5733, 4.736,
-1.67171, 6.22751, -13.7187, 21.0936, -9.69243, -10.5756,
2.15266, 21.2198, -13.0171, -1.43135, 18.8831, 10.6664,
13.8913, 27.3565, 0.472838, -7.40477, -14.8705, 25.7448,
28.402, -2.05484, -9.32712, -17.3169, 15.643, 6.96908,
-15.863, -17.8482, -24.9238, 12.5574, 7.17566, 0.0161972,
5.99291, -41.0228, 1.95791, -6.78012, 9.20162, 4.6234,
-6.33629, -7.61679, 27.7318, -8.9214, -14.1931, 7.88247,
-12.2367, -21.245, -2.5927, 13.7776, -2.7864, -24.5072,
23.15, -9.93687, -2.92559, 3.88086, 11.2667, 11.1998,
9.67437, -9.4269, 6.2582, 36.5694, 2.88654, 1.82052,
15.385, -2.88243, 19.8377, -14.5111, 5.92264, -2.55757,
-20.9648, 3.76147, 18.5074, -13.5547, -7.84261, -19.98,
24.6032, 16.989, -19.1622, 1.35535, -0.0122027, 0.166227,
9.98886, -6.89666, -20.5111, -2.89196, 2.58467, -17.049,
-9.17761, -23.7209, 12.6088, -18.2654, 2.17718, -13.0865,
-9.73326, -12.2682, 6.80914, 20.3469, -10.2912, 4.85191,
-5.19406, 6.78014, 18.0099, 14.3782, -0.124328, -10.0141,
-4.69806, 6.71393, -19.1371, 8.19814, 23.3987, -10.3316,
1.02965, -4.63654, 21.9822, 11.5088, -30.9617, -20.6354,
-33.2824, 31.4666, -11.4837, 11.5144, -1.36834, 9.44599,
-37.5431, -3.16317, -2.09497, -2.62712, 40.4714, -33.0527,
-8.79595, -15.5174, -15.7916, 7.97003, 37.2542, 40.7063,
-14.7261, -12.6884, 2.42105, -10.2686, 25.9033, 14.8525,
22.9598, -16.6224, -3.64949, 4.44269, -22.3897, 13.6968,
-10.874, 4.18931, -24.2284, -3.63764, -15.1379, 40.9515,
28.2393, -8.63225, -12.544, 28.8282, -0.987894, -4.9824,
-25.0777, -0.481678, -3.37082, 5.55114, -9.89898, -8.07628,
23.3581, 3.12034, -8.63348, 0.63042, -18.2216, -22.1886,
44.9505, 19.8267, 23.7129, 8.58075, 7.80458, 1.78796,
-8.13112, -2.1262, -7.12776, -25.0529, -16.7287, 8.41402,
2.01965, 19.2579, 20.0963, 5.99199, 28.1098, 5.96128,
2.42493, -6.33216, -26.5858, -23.8607, 8.27049, 3.05805,
0.0153248, 0.446112, -4.92759, 19.0023, 22.7346, 15.5451,
-7.39591, 40.285, 10.8414, 25.7961, -8.81069, -13.5,
5.81306, 11.2384, 6.93765, -9.43067, 9.51418, 22.9709,
-9.17611, -16.4993, -1.56929, -2.9111, 4.17113, 10.9228,
10.0376, -27.4993, -8.25332, -1.715, -11.5063, -10.467,
23.6637, -13.8338, 14.7284, 8.00341, -2.71881, -8.80708,
27.101, 2.42801, 11.4599, -24.1577, -20.9901, 4.52358,
16.8065, 19.3315, 11.1219, 13.3391, -13.1522, 0.91428,
-25.2603, 6.04837, 12.1994, 21.9372, 14.8795, 6.93368,
-1.24639, -7.96856, 16.4064, -2.36409, -25.9093, 46.0938,
8.81687, 24.8004, 11.4475, -13.261, -19.8693, -28.4793,
15.3175, -12.5335, 24.1778, 10.5133, 22.2244, 9.93191,
-18.7982, 38.939, -20.0631, -35.4052, 7.5879, -0.599373,
-18.1388, 9.5843, 17.4375, -21.057, 8.1634, 6.31216,
-61.5486, -8.71159, 19.7502, -25.2365, 3.56558, -1.64973,
-26.9863, 0.291017, -12.5337, -10.505, 11.0614, 4.84072,
-0.630579, -3.87056, -0.707795, -13.1306, -19.6548, -16.2436,
4.87022, -5.90744, 3.46971, -40.0866, 16.8741, 10.3333,
-1.00985, 16.234, -0.475836, 28.3848, 1.75473, 28.2608
};
const struct lsp_codebook lspmelvq_cb[] = {
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lspmelvq1.txt */
{
6,
6,
64,
codes0
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lspmelvq2.txt */
{
6,
6,
64,
codes1
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/lspmelvq3.txt */
{
6,
6,
64,
codes2
},
{ 0, 0, 0, 0 }
};
+121
View File
@@ -0,0 +1,121 @@
/* THIS IS A GENERATED FILE. Edit generate_codebook.c and its input */
/*
* This intermediary file and the files that used to create it are under
* The LGPL. See the file COPYING.
*/
#include "defines.h"
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel1.txt */
static const float codes0[] = {
550,
600,
650,
700,
750,
800,
850,
900
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel2.txt */
static const float codes1[] = {
50,
100,
200,
300
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel3.txt */
static const float codes2[] = {
800,
850,
900,
950,
1000,
1050,
1100,
1150,
1200,
1250,
1300,
1350,
1400,
1450,
1500,
1650
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel4.txt */
static const float codes3[] = {
25,
50,
75,
100,
125,
150,
175,
250
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel5.txt */
static const float codes4[] = {
1350,
1400,
1450,
1500,
1550,
1600,
1650,
1700
};
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel6.txt */
static const float codes5[] = {
25,
50,
100,
150
};
const struct lsp_codebook mel_cb[] = {
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel1.txt */
{
1,
3,
8,
codes0
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel2.txt */
{
1,
2,
4,
codes1
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel3.txt */
{
1,
4,
16,
codes2
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel4.txt */
{
1,
3,
8,
codes3
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel5.txt */
{
1,
3,
8,
codes4
},
/* /Users/brandon/freetel-code/codec2/branches/0.6/src/codebook/mel6.txt */
{
1,
2,
4,
codes5
},
{ 0, 0, 0, 0 }
};
File diff suppressed because it is too large Load Diff
+69
View File
@@ -0,0 +1,69 @@
/*---------------------------------------------------------------------------*\
FILE........: codec2.h
AUTHOR......: David Rowe
DATE CREATED: 21 August 2010
Codec 2 fully quantised encoder and decoder functions. If you want use
Codec 2, these are the functions you need to call.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2010 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __CODEC2__
#define __CODEC2__
#define CODEC2_MODE_3200 0
#define CODEC2_MODE_2400 1
#define CODEC2_MODE_1600 2
#define CODEC2_MODE_1400 3
#define CODEC2_MODE_1300 4
#define CODEC2_MODE_1200 5
#define CODEC2_MODE_700 6
#define CODEC2_MODE_700B 7
#define CODEC2_MODE_700C 8
struct CODEC2;
struct CODEC2 * codec2_create(int mode);
void codec2_destroy(struct CODEC2 *codec2_state);
void codec2_encode(struct CODEC2 *codec2_state, unsigned char * bits, short speech_in[]);
void codec2_decode(struct CODEC2 *codec2_state, short speech_out[], const unsigned char *bits);
void codec2_decode_ber(struct CODEC2 *codec2_state, short speech_out[], const unsigned char *bits, float ber_est);
int codec2_samples_per_frame(struct CODEC2 *codec2_state);
int codec2_bits_per_frame(struct CODEC2 *codec2_state);
void codec2_set_lpc_post_filter(struct CODEC2 *codec2_state, int enable, int bass_boost, float beta, float gamma);
int codec2_get_spare_bit_index(struct CODEC2 *codec2_state);
int codec2_rebuild_spare_bit(struct CODEC2 *codec2_state, int unpacked_bits[]);
void codec2_set_natural_or_gray(struct CODEC2 *codec2_state, int gray);
void codec2_set_softdec(struct CODEC2 *c2, float *softdec);
float codec2_get_energy(struct CODEC2 *codec2_state, const unsigned char *bits);
#endif
#ifdef __cplusplus
}
#endif
+68
View File
@@ -0,0 +1,68 @@
/*---------------------------------------------------------------------------*\
FILE........: codec2_cohpsk.h
AUTHOR......: David Rowe
DATE CREATED: March 2015
Functions that implement a coherent PSK FDM modem.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2015 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CODEC2_COHPSK__
#define __CODEC2_COHPSK__
#define COHPSK_BITS_PER_FRAME 56 /* hard coded for now */
#define COHPSK_NC 7 /* hard coded for now */
#define COHPSK_NOM_SAMPLES_PER_FRAME 600
#define COHPSK_MAX_SAMPLES_PER_FRAME 625
#define COHPSK_RS 75
#define COHPSK_FS 7500 /* note this is a wierd
value to get an integer
oversampling rate */
#include "comp.h"
#include "modem_stats.h"
struct COHPSK;
extern const int test_bits_coh[];
struct COHPSK *cohpsk_create(void);
void cohpsk_destroy(struct COHPSK *coh);
void cohpsk_mod(struct COHPSK *cohpsk, COMP tx_fdm[], int tx_bits[], int nbits);
void cohpsk_clip(COMP tx_fdm[]);
void cohpsk_demod(struct COHPSK *cohpsk, float rx_bits[], int *sync, COMP rx_fdm[], int *nin_frame);
void cohpsk_get_demod_stats(struct COHPSK *cohpsk, struct MODEM_STATS *stats);
void cohpsk_set_verbose(struct COHPSK *coh, int verbose);
void cohpsk_get_test_bits(struct COHPSK *coh, int rx_bits[]);
void cohpsk_put_test_bits(struct COHPSK *coh, int *state, short error_pattern[],
int *bit_errors, char rx_bits[], int channel);
int cohpsk_error_pattern_size(void);
void cohpsk_set_frame(struct COHPSK *coh, int frame);
void fdmdv_freq_shift_coh(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, float Fs,
COMP *foff_phase_rect, int nin);
/* used for accessing upper and lower bits before diversity combination */
float *cohpsk_get_rx_bits_lower(struct COHPSK *coh);
float *cohpsk_get_rx_bits_upper(struct COHPSK *coh);
void cohpsk_set_carrier_ampl(struct COHPSK *coh, int c, float ampl);
#endif
+113
View File
@@ -0,0 +1,113 @@
/*---------------------------------------------------------------------------*\
FILE........: codec2_fdmdv.h
AUTHOR......: David Rowe
DATE CREATED: April 14 2012
A 1400 bit/s (nominal) Frequency Division Multiplexed Digital Voice
(FDMDV) modem. Used for digital audio over HF SSB. See
README_fdmdv.txt for more information, and fdmdv_mod.c and
fdmdv_demod.c for example usage.
The name codec2_fdmdv.h is used to make it unique when "make
installed".
References:
[1] http://n1su.com/fdmdv/FDMDV_Docs_Rel_1_4b.pdf
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2012 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FDMDV__
#define __FDMDV__
#ifdef __cplusplus
extern "C" {
#endif
/* set up the calling convention for DLL function import/export for
WIN32 cross compiling */
#ifdef __CODEC2_WIN32__
#ifdef __CODEC2_BUILDING_DLL__
#define CODEC2_WIN32SUPPORT __declspec(dllexport) __stdcall
#else
#define CODEC2_WIN32SUPPORT __declspec(dllimport) __stdcall
#endif
#else
#define CODEC2_WIN32SUPPORT
#endif
#include "comp.h"
#include "modem_stats.h"
#define FDMDV_NC 14 /* default number of data carriers */
#define FDMDV_NC_MAX 20 /* maximum number of data carriers */
#define FDMDV_BITS_PER_FRAME 28 /* 20ms frames, for nominal 1400 bit/s */
#define FDMDV_NOM_SAMPLES_PER_FRAME 160 /* modulator output samples/frame and nominal demod samples/frame */
/* at 8000 Hz sample rate */
#define FDMDV_MAX_SAMPLES_PER_FRAME 200 /* max demod samples/frame, use this to allocate storage */
#define FDMDV_SCALE 1000 /* suggested scaling for 16 bit shorts */
#define FDMDV_FCENTRE 1500 /* Centre frequency, Nc/2 carriers below this, Nc/2 carriers above (Hz) */
/* 8 to 48 kHz sample rate conversion */
#define FDMDV_OS 2 /* oversampling rate */
#define FDMDV_OS_TAPS_16K 48 /* number of OS filter taps at 16kHz */
#define FDMDV_OS_TAPS_8K (FDMDV_OS_TAPS_16K/FDMDV_OS) /* number of OS filter taps at 8kHz */
/* FDMDV states and stats structures */
struct FDMDV;
struct FDMDV * fdmdv_create(int Nc);
void fdmdv_destroy(struct FDMDV *fdmdv_state);
void fdmdv_use_old_qpsk_mapping(struct FDMDV *fdmdv_state);
int fdmdv_bits_per_frame(struct FDMDV *fdmdv_state);
float fdmdv_get_fsep(struct FDMDV *fdmdv_state);
void fdmdv_set_fsep(struct FDMDV *fdmdv_state, float fsep);
void fdmdv_mod(struct FDMDV *fdmdv_state, COMP tx_fdm[], int tx_bits[], int *sync_bit);
void fdmdv_demod(struct FDMDV *fdmdv_state, int rx_bits[], int *reliable_sync_bit, COMP rx_fdm[], int *nin);
void fdmdv_get_test_bits(struct FDMDV *fdmdv_state, int tx_bits[]);
int fdmdv_error_pattern_size(struct FDMDV *fdmdv_state);
void fdmdv_put_test_bits(struct FDMDV *f, int *sync, short error_pattern[], int *bit_errors, int *ntest_bits, int rx_bits[]);
void fdmdv_get_demod_stats(struct FDMDV *fdmdv_state, struct MODEM_STATS *stats);
void fdmdv_8_to_16(float out16k[], float in8k[], int n);
void fdmdv_8_to_16_short(short out16k[], short in8k[], int n);
void fdmdv_16_to_8(float out8k[], float in16k[], int n);
void fdmdv_16_to_8_short(short out8k[], short in16k[], int n);
void fdmdv_freq_shift(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, COMP *foff_phase_rect, int nin);
/* debug/development function(s) */
void fdmdv_dump_osc_mags(struct FDMDV *f);
void fdmdv_simulate_channel(float *sig_pwr_av, COMP samples[], int nin, float target_snr);
#ifdef __cplusplus
}
#endif
#endif
+155
View File
@@ -0,0 +1,155 @@
/*
* codec2_fft.c
*
* Created on: 24.09.2016
* Author: danilo
*/
#include "codec2_fft.h"
#ifdef USE_KISS_FFT
#include "_kiss_fft_guts.h"
#else
#if 0
// caching constants in RAM did not seem to have an effect on performance
// TODO: Decide what to with this code
#define FFT_INIT_CACHE_SIZE 4
const arm_cfft_instance_f32* fft_init_cache[FFT_INIT_CACHE_SIZE];
static const arm_cfft_instance_f32* arm_fft_instance2ram(const arm_cfft_instance_f32* in)
{
arm_cfft_instance_f32* out = malloc(sizeof(arm_cfft_instance_f32));
if (out) {
memcpy(out,in,sizeof(arm_cfft_instance_f32));
out->pBitRevTable = malloc(out->bitRevLength * sizeof(uint16_t));
out->pTwiddle = malloc(out->fftLen * sizeof(float32_t));
memcpy((void*)out->pBitRevTable,in->pBitRevTable,out->bitRevLength * sizeof(uint16_t));
memcpy((void*)out->pTwiddle,in->pTwiddle,out->fftLen * sizeof(float32_t));
}
return out;
}
static const arm_cfft_instance_f32* arm_fft_cache_get(const arm_cfft_instance_f32* romfft)
{
const arm_cfft_instance_f32* retval = NULL;
static int used = 0;
for (int i = 0; fft_init_cache[i] != NULL && i < used; i++)
{
if (romfft->fftLen == fft_init_cache[i]->fftLen)
{
retval = fft_init_cache[i];
break;
}
}
if (retval == NULL && used < FFT_INIT_CACHE_SIZE)
{
retval = arm_fft_instance2ram(romfft);
fft_init_cache[used++] = retval;
}
if (retval == NULL)
{
retval = romfft;
}
return retval;
}
#endif
#endif
void codec2_fft_free(codec2_fft_cfg cfg)
{
#ifdef USE_KISS_FFT
KISS_FFT_FREE(cfg);
#else
free(cfg);
#endif
}
codec2_fft_cfg codec2_fft_alloc(int nfft, int inverse_fft, void* mem, size_t* lenmem)
{
codec2_fft_cfg retval;
#ifdef USE_KISS_FFT
retval = kiss_fft_alloc(nfft, inverse_fft, mem, lenmem);
#else
retval = malloc(sizeof(codec2_fft_struct));
retval->inverse = inverse_fft;
switch(nfft)
{
case 128:
retval->instance = &arm_cfft_sR_f32_len128;
break;
case 256:
retval->instance = &arm_cfft_sR_f32_len256;
break;
case 512:
retval->instance = &arm_cfft_sR_f32_len512;
break;
// case 1024:
// retval->instance = &arm_cfft_sR_f32_len1024;
// break;
default:
abort();
}
// retval->instance = arm_fft_cache_get(retval->instance);
#endif
return retval;
}
codec2_fftr_cfg codec2_fftr_alloc(int nfft, int inverse_fft, void* mem, size_t* lenmem)
{
codec2_fftr_cfg retval;
#ifdef USE_KISS_FFT
retval = kiss_fftr_alloc(nfft, inverse_fft, mem, lenmem);
#else
retval = malloc(sizeof(codec2_fftr_struct));
retval->inverse = inverse_fft;
retval->instance = malloc(sizeof(arm_rfft_fast_instance_f32));
arm_rfft_fast_init_f32(retval->instance,nfft);
// memcpy(&retval->instance->Sint,arm_fft_cache_get(&retval->instance->Sint),sizeof(arm_cfft_instance_f32));
#endif
return retval;
}
void codec2_fftr_free(codec2_fftr_cfg cfg)
{
#ifdef USE_KISS_FFT
KISS_FFT_FREE(cfg);
#else
free(cfg->instance);
free(cfg);
#endif
}
// there is a little overhead for inplace kiss_fft but this is
// on the powerful platforms like the Raspberry or even x86 PC based ones
// not noticeable
// the reduced usage of RAM and increased performance on STM32 platforms
// should be worth it.
void codec2_fft_inplace(codec2_fft_cfg cfg, codec2_fft_cpx* inout)
{
#ifdef USE_KISS_FFT
kiss_fft_cpx in[512];
// decide whether to use the local stack based buffer for in
// or to allow kiss_fft to allocate RAM
// second part is just to play safe since first method
// is much faster and uses less RAM
if (cfg->nfft <= 512)
{
memcpy(in,inout,cfg->nfft*sizeof(kiss_fft_cpx));
kiss_fft(cfg, in, (kiss_fft_cpx*)inout);
}
else
{
kiss_fft(cfg, (kiss_fft_cpx*)inout, (kiss_fft_cpx*)inout);
}
#else
arm_cfft_f32(cfg->instance,(float*)inout,cfg->inverse,1);
if (cfg->inverse)
{
arm_scale_f32(inout,cfg->instance->fftLen,inout,cfg->instance->fftLen*2);
}
#endif
}
+110
View File
@@ -0,0 +1,110 @@
/*
* codec2_fft.h
*
* Created on: 17.09.2016
* Author: danilo
*/
#ifndef DRIVERS_FREEDV_CODEC2_FFT_H_
#define DRIVERS_FREEDV_CODEC2_FFT_H_
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifdef ARM_MATH_CM4
#include "stm32f4xx.h"
#include "core_cm4.h"
#include "arm_math.h"
#include "arm_const_structs.h"
#endif
#include "defines.h"
#include "comp.h"
#ifndef ARM_MATH_CM4
#define USE_KISS_FFT
#endif
// #define USE_KISS_FFT
typedef COMP codec2_fft_cpx;
#include "kiss_fftr.h"
#ifdef USE_KISS_FFT
#include "kiss_fft.h"
typedef kiss_fftr_cfg codec2_fftr_cfg;
typedef kiss_fft_cfg codec2_fft_cfg;
typedef kiss_fft_scalar codec2_fft_scalar;
#else
typedef float32_t codec2_fft_scalar;
typedef struct {
arm_rfft_fast_instance_f32* instance;
int inverse;
} codec2_fftr_struct;
typedef codec2_fftr_struct* codec2_fftr_cfg;
typedef struct {
const arm_cfft_instance_f32* instance;
int inverse;
} codec2_fft_struct;
typedef codec2_fft_struct* codec2_fft_cfg;
#endif
static inline void codec2_fftr(codec2_fftr_cfg cfg, codec2_fft_scalar* in, codec2_fft_cpx* out)
{
#ifdef USE_KISS_FFT
kiss_fftr(cfg, in, (kiss_fft_cpx*)out);
#else
arm_rfft_fast_f32(cfg->instance,in,(float*)out,cfg->inverse);
out->imag = 0; // remove out[FFT_ENC/2]->real stored in out[0].imag
#endif
}
static inline void codec2_fftri(codec2_fftr_cfg cfg, codec2_fft_cpx* in, codec2_fft_scalar* out)
{
#ifdef USE_KISS_FFT
kiss_fftri(cfg, (kiss_fft_cpx*)in, out);
#else
arm_rfft_fast_f32(cfg->instance,(float*)in,out,cfg->inverse);
// arm_scale_f32(out,cfg->instance->fftLenRFFT,out,cfg->instance->fftLenRFFT);
#endif
}
codec2_fft_cfg codec2_fft_alloc(int nfft, int inverse_fft, void* mem, size_t* lenmem);
codec2_fftr_cfg codec2_fftr_alloc(int nfft, int inverse_fft, void* mem, size_t* lenmem);
void codec2_fft_free(codec2_fft_cfg cfg);
void codec2_fftr_free(codec2_fftr_cfg cfg);
static inline void codec2_fft(codec2_fft_cfg cfg, codec2_fft_cpx* in, codec2_fft_cpx* out)
{
#ifdef USE_KISS_FFT
kiss_fft(cfg, (kiss_fft_cpx*)in, (kiss_fft_cpx*)out);
#else
memcpy(out,in,cfg->instance->fftLen*2*sizeof(float));
arm_cfft_f32(cfg->instance,(float*)out,cfg->inverse,0);
// TODO: this is not nice, but for now required to keep changes minimal
// however, since main goal is to reduce the memory usage
// we should convert to an in place interface
// on PC like platforms the overhead of using the "inplace" kiss_fft calls
// is neglectable compared to the gain in memory usage on STM32 platforms
if (cfg->inverse)
{
arm_scale_f32((float*)out,cfg->instance->fftLen,(float*)out,cfg->instance->fftLen*2);
}
#endif
}
void codec2_fft_inplace(codec2_fft_cfg cfg, codec2_fft_cpx* inout);
#endif
+60
View File
@@ -0,0 +1,60 @@
/*---------------------------------------------------------------------------*\
FILE........: codec2_fifo.h
AUTHOR......: David Rowe
DATE CREATED: Oct 15 2012
A FIFO design useful in gluing the FDMDV modem and codec together in
integrated applications.
The name codec2_fifo.h is used to make it unique when "make
installed".
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2012 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FIFO__
#define __FIFO__
#ifdef __cplusplus
extern "C" {
#endif
struct FIFO;
struct FIFO *fifo_create(int nshort);
void fifo_destroy(struct FIFO *fifo);
int fifo_write(struct FIFO *fifo, short data[], int n);
int fifo_read(struct FIFO *fifo, short data[], int n);
/*!
* Return the number of bytes stored in the FIFO.
*/
int fifo_used(const struct FIFO * const fifo);
/*!
* Return the space available in the FIFO.
*/
int fifo_free(const struct FIFO * const fifo);
#ifdef __cplusplus
}
#endif
#endif
+53
View File
@@ -0,0 +1,53 @@
/*---------------------------------------------------------------------------*\
FILE........: codec2_fm.h
AUTHOR......: David Rowe
DATE CREATED: February 2015
Functions that implement analog FM, see also octave/fm.m.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2015 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CODEC2_FM__
#define __CODEC2_FM__
#include "comp.h"
struct FM {
float Fs; /* setme: sample rate */
float fm_max; /* setme: maximum modulation frequency */
float fd; /* setme: maximum deviation */
float fc; /* setme: carrier frequency */
COMP *rx_bb;
COMP rx_bb_filt_prev;
float *rx_dem_mem;
float tx_phase;
int nsam;
COMP lo_phase;
};
struct FM *fm_create(int nsam);
void fm_destroy(struct FM *fm_states);
void fm_demod(struct FM *fm, float rx_out[], float rx[]);
void fm_mod(struct FM *fm, float tx_in[], float tx_out[]);
void fm_mod_comp(struct FM *fm_states, float tx_in[], COMP tx_out[]);
#endif
+83
View File
@@ -0,0 +1,83 @@
/*---------------------------------------------------------------------------*\
FILE........: codec2_internal.h
AUTHOR......: David Rowe
DATE CREATED: April 16 2012
Header file for Codec2 internal states, exposed via this header
file to assist in testing.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2012 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CODEC2_INTERNAL__
#define __CODEC2_INTERNAL__
#include "codec2_fft.h"
struct CODEC2 {
int mode;
C2CONST c2const;
int Fs;
int n_samp;
int m_pitch;
codec2_fft_cfg fft_fwd_cfg; /* forward FFT config */
codec2_fftr_cfg fftr_fwd_cfg; /* forward real FFT config */
float *w; /* [m_pitch] time domain hamming window */
COMP W[FFT_ENC]; /* DFT of w[] */
float *Pn; /* [2*n_samp] trapezoidal synthesis window */
float *bpf_buf; /* buffer for band pass filter */
float *Sn; /* [m_pitch] input speech */
float hpf_states[2]; /* high pass filter states */
void *nlp; /* pitch predictor states */
int gray; /* non-zero for gray encoding */
codec2_fftr_cfg fftr_inv_cfg; /* inverse FFT config */
float *Sn_; /* [2*n_samp] synthesised output speech */
float ex_phase; /* excitation model phase track */
float bg_est; /* background noise estimate for post filter */
float prev_f0_enc; /* previous frame's f0 estimate */
MODEL prev_model_dec; /* previous frame's model parameters */
float prev_lsps_dec[LPC_ORD]; /* previous frame's LSPs */
float prev_e_dec; /* previous frame's LPC energy */
int lpc_pf; /* LPC post filter on */
int bass_boost; /* LPC post filter bass boost */
float beta; /* LPC post filter parameters */
float gamma;
float xq_enc[2]; /* joint pitch and energy VQ states */
float xq_dec[2];
int smoothing; /* enable smoothing for channels with errors */
float *softdec; /* optional soft decn bits from demod */
/* newamp1 states */
float Wo_left;
int voicing_left;
codec2_fft_cfg phase_fft_fwd_cfg;
codec2_fft_cfg phase_fft_inv_cfg;
};
// test and debug
void analyse_one_frame(struct CODEC2 *c2, MODEL *model, short speech[]);
void synthesise_one_frame(struct CODEC2 *c2, short speech[], MODEL *model,
COMP Aw[]);
#endif
+69
View File
@@ -0,0 +1,69 @@
/*---------------------------------------------------------------------------*\
FILE........: codec2_ofdm.h
AUTHORS.....: David Rowe & Steve Sampson
DATE CREATED: June 2017
External user references to the modem library.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2017 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CODEC2_OFDM_H
#define CODEC2_OFDM_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes */
#include <complex.h>
#include <stdbool.h>
#include "comp.h"
/* Defines */
struct OFDM;
/* Prototypes */
struct OFDM *ofdm_create(void);
void ofdm_destroy(struct OFDM *);
void ofdm_mod(struct OFDM *, COMP *, const int *);
void ofdm_demod(struct OFDM *, int *, COMP *);
int ofdm_get_nin(struct OFDM *);
int ofdm_get_samples_per_frame(void);
int ofdm_get_max_samples_per_frame(void);
/* option setters */
void ofdm_set_verbose(struct OFDM *, int);
void ofdm_set_timing_enable(struct OFDM *, bool);
void ofdm_set_foff_est_enable(struct OFDM *, bool);
void ofdm_set_phase_est_enable(struct OFDM *, bool);
void ofdm_set_off_est_hz(struct OFDM *, float);
#ifdef __cplusplus
}
#endif
#endif
+9
View File
@@ -0,0 +1,9 @@
/* Generated by write_pilot_file() Octave function */
#define NSYMROW 4 /* number of data symbols per carrier (number of rows) */
#define NS 4 /* number of data symbols between pilots */
#define NPILOTSFRAME 2 /* number of pilot symbols per carrier */
#define PILOTS_NC 7 /* number of carriers */
#define NSYMROWPILOT 6 /* number of rows after pilots inserted */
+124
View File
@@ -0,0 +1,124 @@
/*---------------------------------------------------------------------------*\
FILE........: cohpsk_internal.h
AUTHOR......: David Rowe
DATE CREATED: March 2015
Functions that implement a coherent PSK FDM modem.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2015 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __COHPSK_INTERNAL__
#define __COHPSK_INTERNAL__
#define NCT_SYMB_BUF (2*NSYMROWPILOT+2)
#define ND 2 /* diversity factor ND 1 is no diveristy, ND we have orginal plus
one copy */
#define NSW 4 /* number of sync window frames */
#define COHPSK_ND 2 /* diversity factor */
#define COHPSK_M 100 /* oversampling rate */
#define COHPSK_NSYM 6
#define COHPSK_NFILTER (COHPSK_NSYM*COHPSK_M)
#define COHPSK_EXCESS_BW 0.5 /* excess BW factor of root nyq filter */
#define COHPSK_NT 5 /* number of symbols we estimate timing over */
#define COHPSK_CLIP 6.5 /* hard clipping for Nc*Nc=14 to reduce PAPR */
#include "fdmdv_internal.h"
#include "kiss_fft.h"
struct COHPSK {
COMP ch_fdm_frame_buf[NSW*NSYMROWPILOT*COHPSK_M]; /* buffer of several frames of symbols from channel */
float pilot2[2*NPILOTSFRAME][COHPSK_NC];
float phi_[NSYMROWPILOT][COHPSK_NC*ND]; /* phase estimates for this frame of rx data symbols */
float amp_[NSYMROW][COHPSK_NC*ND]; /* amplitude estimates for this frame of rx data symbols */
COMP rx_symb[NSYMROWPILOT][COHPSK_NC*ND]; /* demodulated symbols */
float f_est;
COMP rx_filter_memory[COHPSK_NC*ND][COHPSK_NFILTER];
COMP ct_symb_buf[NCT_SYMB_BUF][COHPSK_NC*ND];
int ct; /* coarse timing offset in symbols */
float rx_timing; /* fine timing for last symbol in frame */
int nin; /* number of samples to input for next symbol */
float f_fine_est;
COMP ff_rect;
COMP ff_phase;
COMP ct_symb_ff_buf[NSYMROWPILOT+2][COHPSK_NC*ND];
int sync;
int sync_timer;
int frame;
float ratio;
float sig_rms;
float noise_rms;
struct FDMDV *fdmdv;
int verbose;
int *ptest_bits_coh_tx;
int *ptest_bits_coh_rx[2];
int *ptest_bits_coh_end;
/* counting bit errors using pilots */
int npilotbits;
int npilotbiterrors;
/* optional log variables used for testing Octave to C port */
COMP *rx_baseband_log;
int rx_baseband_log_col_index;
int rx_baseband_log_col_sz;
COMP *rx_filt_log;
int rx_filt_log_col_index;
int rx_filt_log_col_sz;
COMP *ch_symb_log;
int ch_symb_log_r;
int ch_symb_log_col_sz;
float *rx_timing_log;
int rx_timing_log_index;
/* demodulated bits before diversity combination for test/instrumentation purposes */
float rx_bits_lower[COHPSK_BITS_PER_FRAME];
float rx_bits_upper[COHPSK_BITS_PER_FRAME];
/* tx amplitude weights for each carrier for test/instrumentation */
float carrier_ampl[COHPSK_NC*ND];
};
void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC*COHPSK_ND], int tx_bits[], int nbits);
void qpsk_symbols_to_bits(struct COHPSK *coh, float rx_bits[], COMP ct_symb_buf[][COHPSK_NC*COHPSK_ND]);
void tx_filter_and_upconvert_coh(COMP tx_fdm[], int Nc, COMP tx_symbols[],
COMP tx_filter_memory[COHPSK_NC][COHPSK_NSYM],
COMP phase_tx[], COMP freq[],
COMP *fbb_phase, COMP fbb_rect);
void fdm_downconvert_coh(COMP rx_baseband[COHPSK_NC][COHPSK_M+COHPSK_M/P], int Nc, COMP rx_fdm[], COMP phase_rx[], COMP freq[], int nin);
void rx_filter_coh(COMP rx_filt[COHPSK_NC+1][P+1], int Nc, COMP rx_baseband[COHPSK_NC+1][COHPSK_M+COHPSK_M/P], COMP rx_filter_memory[COHPSK_NC+1][COHPSK_NFILTER], int nin);
void frame_sync_fine_freq_est(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC*COHPSK_ND], int sync, int *next_sync);
void fine_freq_correct(struct COHPSK *coh, int sync, int next_sync);
int sync_state_machine(struct COHPSK *coh, int sync, int next_sync);
int cohpsk_fs_offset(COMP out[], COMP in[], int n, float sample_rate_ppm);
#endif
+38
View File
@@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------*\
FILE........: comp.h
AUTHOR......: David Rowe
DATE CREATED: 24/08/09
Complex number definition.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __COMP__
#define __COMP__
/* Complex number */
typedef struct {
float real;
float imag;
} COMP;
#endif
+141
View File
@@ -0,0 +1,141 @@
/*---------------------------------------------------------------------------*\
FILE........: comp_prim.h
AUTHOR......: David Rowe
DATE CREATED: Marh 2015
Complex number maths primitives.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2015 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __COMP_PRIM__
#define __COMP_PRIM__
/*---------------------------------------------------------------------------*\
FUNCTIONS
\*---------------------------------------------------------------------------*/
inline static COMP cneg(COMP a)
{
COMP res;
res.real = -a.real;
res.imag = -a.imag;
return res;
}
inline static COMP cconj(COMP a)
{
COMP res;
res.real = a.real;
res.imag = -a.imag;
return res;
}
inline static COMP cmult(COMP a, COMP b)
{
COMP res;
res.real = a.real*b.real - a.imag*b.imag;
res.imag = a.real*b.imag + a.imag*b.real;
return res;
}
inline static COMP fcmult(float a, COMP b)
{
COMP res;
res.real = a*b.real;
res.imag = a*b.imag;
return res;
}
inline static COMP cadd(COMP a, COMP b)
{
COMP res;
res.real = a.real + b.real;
res.imag = a.imag + b.imag;
return res;
}
inline static float cabsolute(COMP a)
{
return sqrtf(powf(a.real, 2.0) + powf(a.imag, 2.0));
}
/*
* Euler's formula in a new convenient function
*/
inline static COMP comp_exp_j(float phi){
COMP res;
res.real = cosf(phi);
res.imag = sinf(phi);
return res;
}
/*
* Quick and easy complex 0
*/
inline static COMP comp0(){
COMP res;
res.real = 0;
res.imag = 0;
return res;
}
/*
* Quick and easy complex subtract
*/
inline static COMP csub(COMP a, COMP b){
COMP res;
res.real = a.real-b.real;
res.imag = a.imag-b.imag;
return res;
}
/*
* Compare the magnitude of a and b. if |a|>|b|, return true, otw false.
* This needs no square roots
*/
inline static int comp_mag_gt(COMP a,COMP b){
return ((a.real*a.real)+(a.imag*a.imag)) > ((b.real*b.real)+(b.imag*b.imag));
}
/*
* Normalize a complex number's magnitude to 1
*/
inline static COMP comp_normalize(COMP a){
COMP b;
float av = cabsolute(a);
b.real = a.real/av;
b.imag = a.imag/av;
return b;
}
#endif
+113
View File
@@ -0,0 +1,113 @@
/*---------------------------------------------------------------------------*\
FILE........: defines.h
AUTHOR......: David Rowe
DATE CREATED: 23/4/93
Defines and structures used throughout the codec.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __DEFINES__
#define __DEFINES__
/*---------------------------------------------------------------------------*\
DEFINES
\*---------------------------------------------------------------------------*/
/* General defines */
#define N_S 0.010 /* buffer size in s */
#define TW_S 0.005 /* trapezoidal synth window overlap */
#define MAX_AMP 160 /* maximum number of harmonics */
#ifndef PI
#define PI 3.141592654 /* mathematical constant */
#endif
#define TWO_PI 6.283185307 /* mathematical constant */
#define MAX_STR 2048 /* maximum string size */
#define FFT_ENC 512 /* size of FFT used for encoder */
#define FFT_DEC 512 /* size of FFT used in decoder */
#define V_THRESH 6.0 /* voicing threshold in dB */
#define LPC_ORD 10 /* LPC order */
#define LPC_ORD_LOW 6 /* LPC order for lower rates */
/* Pitch estimation defines */
#define M_PITCH_S 0.0400 /* pitch analysis window in s */
#define P_MIN_S 0.0025 /* minimum pitch period in s */
#define P_MAX_S 0.0200 /* maximum pitch period in s */
/*---------------------------------------------------------------------------*\
TYPEDEFS
\*---------------------------------------------------------------------------*/
/* Structure to hold constants calculated at run time based on sample rate */
typedef struct {
int Fs; /* sample rate of this instance */
int n_samp; /* number of samples per 10ms frame at Fs */
int max_amp; /* maximum number of harmonics */
int m_pitch; /* pitch estimation window size in samples */
int p_min; /* minimum pitch period in samples */
int p_max; /* maximum pitch period in samples */
float Wo_min;
float Wo_max;
int nw; /* analysis window size in samples */
int tw; /* trapezoidal synthesis window overlap */
} C2CONST;
/* Structure to hold model parameters for one frame */
typedef struct {
float Wo; /* fundamental frequency estimate in radians */
int L; /* number of harmonics */
float A[MAX_AMP+1]; /* amplitiude of each harmonic */
float phi[MAX_AMP+1]; /* phase of each harmonic */
int voiced; /* non-zero if this frame is voiced */
} MODEL;
/* describes each codebook */
struct lsp_codebook {
int k; /* dimension of vector */
int log2m; /* number of bits in m */
int m; /* elements in codebook */
const float * cb; /* The elements */
};
extern const struct lsp_codebook lsp_cb[];
extern const struct lsp_codebook lsp_cbd[];
extern const struct lsp_codebook lsp_cbvq[];
extern const struct lsp_codebook lsp_cbjnd[];
extern const struct lsp_codebook lsp_cbdt[];
extern const struct lsp_codebook lsp_cbjvm[];
extern const struct lsp_codebook lsp_cbvqanssi[];
extern const struct lsp_codebook mel_cb[];
extern const struct lsp_codebook ge_cb[];
extern const struct lsp_codebook lspmelvq_cb[];
extern const struct lsp_codebook newamp1vq_cb[];
extern const struct lsp_codebook newamp1_energy_cb[];
#endif
+674
View File
@@ -0,0 +1,674 @@
/*---------------------------------------------------------------------------*\
FILE........: dump.c
AUTHOR......: David Rowe
DATE CREATED: 25/8/09
Routines to dump data to text files for Octave analysis.
\*---------------------------------------------------------------------------*/
/*
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "defines.h"
#include "comp.h"
#include "dump.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifdef __EMBEDDED__
#include "gdb_stdio.h"
#define fprintf gdb_stdio_fprintf
#define fopen gdb_stdio_fopen
#define fclose gdb_stdio_fclose
#endif
#ifdef DUMP
static int dumpon = 0;
static FILE *fsn = NULL;
static FILE *fsw = NULL;
static FILE *few = NULL;
static FILE *fsw_ = NULL;
static FILE *fsoftdec = NULL;
static FILE *fmodel = NULL;
static FILE *fqmodel = NULL;
static FILE *fpwb = NULL;
static FILE *fpw = NULL;
static FILE *frw = NULL;
static FILE *flsp = NULL;
static FILE *fweights = NULL;
static FILE *flsp_ = NULL;
static FILE *fmel = NULL;
static FILE *fmel_indexes = NULL;
static FILE *fphase = NULL;
static FILE *fphase_ = NULL;
static FILE *ffw = NULL;
static FILE *fe = NULL;
static FILE *fsq = NULL;
static FILE *fdec = NULL;
static FILE *fsnr = NULL;
static FILE *flpcsnr = NULL;
static FILE *fak = NULL;
static FILE *fak_ = NULL;
static FILE *fbg = NULL;
static FILE *fE = NULL;
static FILE *frk = NULL;
static FILE *fhephase = NULL;
static char prefix[MAX_STR];
void dump_on(char p[]) {
dumpon = 1;
strcpy(prefix, p);
}
void dump_off(){
if (fsn != NULL)
fclose(fsn);
if (fsw != NULL)
fclose(fsw);
if (fsw_ != NULL)
fclose(fsw_);
if (few != NULL)
fclose(few);
if (fmodel != NULL)
fclose(fmodel);
if (fsoftdec != NULL)
fclose(fsoftdec);
if (fqmodel != NULL)
fclose(fqmodel);
if (fpwb != NULL)
fclose(fpwb);
if (fpw != NULL)
fclose(fpw);
if (frw != NULL)
fclose(frw);
if (flsp != NULL)
fclose(flsp);
if (fweights != NULL)
fclose(fweights);
if (flsp_ != NULL)
fclose(flsp_);
if (fmel != NULL)
fclose(fmel);
if (fmel_indexes != NULL)
fclose(fmel_indexes);
if (fphase != NULL)
fclose(fphase);
if (fphase_ != NULL)
fclose(fphase_);
if (ffw != NULL)
fclose(ffw);
if (fe != NULL)
fclose(fe);
if (fsq != NULL)
fclose(fsq);
if (fdec != NULL)
fclose(fdec);
if (fsnr != NULL)
fclose(fsnr);
if (flpcsnr != NULL)
fclose(flpcsnr);
if (fak != NULL)
fclose(fak);
if (fak_ != NULL)
fclose(fak_);
if (fbg != NULL)
fclose(fbg);
if (fE != NULL)
fclose(fE);
if (frk != NULL)
fclose(frk);
if (fhephase != NULL)
fclose(fhephase);
}
void dump_Sn(int m_pitch, float Sn[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fsn == NULL) {
sprintf(s,"%s_sn.txt", prefix);
fsn = fopen(s, "wt");
assert(fsn != NULL);
}
/* split across two lines to avoid max line length problems */
/* reconstruct in Octave */
for(i=0; i<m_pitch/2; i++)
fprintf(fsn,"%f\t",Sn[i]);
fprintf(fsn,"\n");
for(i=m_pitch/2; i<m_pitch; i++)
fprintf(fsn,"%f\t",Sn[i]);
fprintf(fsn,"\n");
}
void dump_Sw(COMP Sw[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fsw == NULL) {
sprintf(s,"%s_sw.txt", prefix);
fsw = fopen(s, "wt");
assert(fsw != NULL);
}
for(i=0; i<FFT_ENC/2; i++)
fprintf(fsw,"%f\t",
10.0*log10(Sw[i].real*Sw[i].real + Sw[i].imag*Sw[i].imag));
fprintf(fsw,"\n");
}
void dump_Sw_(COMP Sw_[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fsw_ == NULL) {
sprintf(s,"%s_sw_.txt", prefix);
fsw_ = fopen(s, "wt");
assert(fsw_ != NULL);
}
for(i=0; i<FFT_ENC/2; i++)
fprintf(fsw_,"%f\t",
10.0*log10(Sw_[i].real*Sw_[i].real + Sw_[i].imag*Sw_[i].imag));
fprintf(fsw_,"\n");
}
void dump_Ew(COMP Ew[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (few == NULL) {
sprintf(s,"%s_ew.txt", prefix);
few = fopen(s, "wt");
assert(few != NULL);
}
for(i=0; i<FFT_ENC/2; i++)
fprintf(few,"%f\t",
10.0*log10(Ew[i].real*Ew[i].real + Ew[i].imag*Ew[i].imag));
fprintf(few,"\n");
}
void dump_softdec(float *softdec, int n)
{
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fsoftdec == NULL) {
sprintf(s,"%s_softdec.txt", prefix);
fsoftdec = fopen(s, "wt");
assert(fsoftdec != NULL);
}
for(i=0; i<n; i++)
fprintf(fsoftdec,"%f\t", softdec[i]);
fprintf(fsoftdec,"\n");
}
void dump_model(MODEL *model) {
int l;
char s[MAX_STR];
char line[MAX_STR*10];
if (!dumpon) return;
if (fmodel == NULL) {
sprintf(s,"%s_model.txt", prefix);
fmodel = fopen(s, "wt");
assert(fmodel != NULL);
}
sprintf(line,"%12f %12d ", model->Wo, model->L);
for(l=1; l<=model->L; l++) {
sprintf(s,"%12f ",model->A[l]);
strcat(line, s);
assert(strlen(line) < MAX_STR*10);
}
for(l=model->L+1; l<=MAX_AMP; l++) {
sprintf(s,"%12f ", 0.0);
strcat(line,s);
assert(strlen(line) < MAX_STR*10);
}
sprintf(s,"%d\n",model->voiced);
strcat(line,s);
fprintf(fmodel,"%s",line);
}
void dump_quantised_model(MODEL *model) {
int l;
char s[MAX_STR];
char line[2048];
if (!dumpon) return;
if (fqmodel == NULL) {
sprintf(s,"%s_qmodel.txt", prefix);
fqmodel = fopen(s, "wt");
assert(fqmodel != NULL);
}
sprintf(line,"%12f %12d ", model->Wo, model->L);
for(l=1; l<=model->L; l++) {
sprintf(s,"%12f ",model->A[l]);
strcat(line, s);
}
for(l=model->L+1; l<=MAX_AMP; l++) {
sprintf(s,"%12f ", 0.0);
strcat(line, s);
}
sprintf(s,"%d\n",model->voiced);
strcat(line, s);
fprintf(fqmodel, "%s", line);
}
void dump_phase(float phase[], int L) {
int l;
char s[MAX_STR];
if (!dumpon) return;
if (fphase == NULL) {
sprintf(s,"%s_phase.txt", prefix);
fphase = fopen(s, "wt");
assert(fphase != NULL);
}
for(l=1; l<=L; l++)
fprintf(fphase,"%f\t",phase[l]);
for(l=L+1; l<=MAX_AMP; l++)
fprintf(fphase,"%f\t",0.0);
fprintf(fphase,"\n");
}
void dump_phase_(float phase_[], int L) {
int l;
char s[MAX_STR];
if (!dumpon) return;
if (fphase_ == NULL) {
sprintf(s,"%s_phase_.txt", prefix);
fphase_ = fopen(s, "wt");
assert(fphase_ != NULL);
}
for(l=1; l<=L; l++)
fprintf(fphase_,"%f\t",phase_[l]);
for(l=L+1; l<MAX_AMP; l++)
fprintf(fphase_,"%f\t",0.0);
fprintf(fphase_,"\n");
}
void dump_hephase(int ind[], int dim) {
int m;
char s[MAX_STR];
if (!dumpon) return;
if (fhephase == NULL) {
sprintf(s,"%s_hephase.txt", prefix);
fhephase = fopen(s, "wt");
assert(fhephase != NULL);
}
for(m=0; m<dim; m++)
fprintf(fhephase,"%d\t",ind[m]);
fprintf(fhephase,"\n");
}
void dump_snr(float snr) {
char s[MAX_STR];
if (!dumpon) return;
if (fsnr == NULL) {
sprintf(s,"%s_snr.txt", prefix);
fsnr = fopen(s, "wt");
assert(fsnr != NULL);
}
fprintf(fsnr,"%f\n",snr);
}
void dump_lpc_snr(float snr) {
char s[MAX_STR];
if (!dumpon) return;
if (flpcsnr == NULL) {
sprintf(s,"%s_lpc_snr.txt", prefix);
flpcsnr = fopen(s, "wt");
assert(flpcsnr != NULL);
}
fprintf(flpcsnr,"%f\n",snr);
}
/* Pw "before" post filter so we can plot before and after */
void dump_Pwb(float Pwb[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fpwb == NULL) {
sprintf(s,"%s_pwb.txt", prefix);
fpwb = fopen(s, "wt");
assert(fpwb != NULL);
}
for(i=0; i<FFT_ENC/2; i++)
fprintf(fpwb,"%f\t",Pwb[i]);
fprintf(fpwb,"\n");
}
void dump_Pw(float Pw[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fpw == NULL) {
sprintf(s,"%s_pw.txt", prefix);
fpw = fopen(s, "wt");
assert(fpw != NULL);
}
for(i=0; i<FFT_ENC/2; i++)
fprintf(fpw,"%f\t",Pw[i]);
fprintf(fpw,"\n");
}
void dump_Rw(float Rw[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (frw == NULL) {
sprintf(s,"%s_rw.txt", prefix);
frw = fopen(s, "wt");
assert(frw != NULL);
}
for(i=0; i<FFT_ENC/2; i++)
fprintf(frw,"%f\t",Rw[i]);
fprintf(frw,"\n");
}
void dump_weights(float w[], int order) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fweights == NULL) {
sprintf(s,"%s_weights.txt", prefix);
fweights = fopen(s, "wt");
assert(fweights != NULL);
}
for(i=0; i<order; i++)
fprintf(fweights,"%f\t", w[i]);
fprintf(fweights,"\n");
}
void dump_lsp(float lsp[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (flsp == NULL) {
sprintf(s,"%s_lsp.txt", prefix);
flsp = fopen(s, "wt");
assert(flsp != NULL);
}
for(i=0; i<10; i++)
fprintf(flsp,"%f\t",lsp[i]);
fprintf(flsp,"\n");
}
void dump_lsp_(float lsp_[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (flsp_ == NULL) {
sprintf(s,"%s_lsp_.txt", prefix);
flsp_ = fopen(s, "wt");
assert(flsp_ != NULL);
}
for(i=0; i<10; i++)
fprintf(flsp_,"%f\t",lsp_[i]);
fprintf(flsp_,"\n");
}
void dump_mel(float mel[], int order) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fmel == NULL) {
sprintf(s,"%s_mel.txt", prefix);
fmel = fopen(s, "wt");
assert(fmel != NULL);
}
for(i=0; i<order; i++)
fprintf(fmel,"%f\t",mel[i]);
fprintf(fmel,"\n");
}
void dump_mel_indexes(int mel_indexes[], int order) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fmel_indexes == NULL) {
sprintf(s,"%s_mel_indexes.txt", prefix);
fmel_indexes = fopen(s, "wt");
assert(fmel_indexes != NULL);
}
for(i=0; i<order; i++)
fprintf(fmel_indexes,"%d\t",mel_indexes[i]);
fprintf(fmel_indexes,"\n");
}
void dump_ak(float ak[], int order) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fak == NULL) {
sprintf(s,"%s_ak.txt", prefix);
fak = fopen(s, "wt");
assert(fak != NULL);
}
for(i=0; i<=order; i++)
fprintf(fak,"%f\t",ak[i]);
fprintf(fak,"\n");
}
void dump_ak_(float ak_[], int order) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fak_ == NULL) {
sprintf(s,"%s_ak_.txt", prefix);
fak_ = fopen(s, "wt");
assert(fak_ != NULL);
}
for(i=0; i<=order; i++)
fprintf(fak_,"%f\t",ak_[i]);
fprintf(fak_,"\n");
}
void dump_Fw(COMP Fw[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (ffw == NULL) {
sprintf(s,"%s_fw.txt", prefix);
ffw = fopen(s, "wt");
assert(ffw != NULL);
}
for(i=0; i<256; i++)
fprintf(ffw,"%f\t",Fw[i].real);
fprintf(ffw,"\n");
}
void dump_e(float e_hz[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fe == NULL) {
sprintf(s,"%s_e.txt", prefix);
fe = fopen(s, "wt");
assert(fe != NULL);
}
for(i=0; i<500/2; i++)
fprintf(fe,"%f\t",e_hz[i]);
fprintf(fe,"\n");
for(i=500/2; i<500; i++)
fprintf(fe,"%f\t",e_hz[i]);
fprintf(fe,"\n");
}
void dump_sq(int m_pitch, float sq[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fsq == NULL) {
sprintf(s,"%s_sq.txt", prefix);
fsq = fopen(s, "wt");
assert(fsq != NULL);
}
for(i=0; i<m_pitch/2; i++)
fprintf(fsq,"%f\t",sq[i]);
fprintf(fsq,"\n");
for(i=m_pitch/2; i<m_pitch; i++)
fprintf(fsq,"%f\t",sq[i]);
fprintf(fsq,"\n");
}
void dump_dec(COMP Fw[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (fdec == NULL) {
sprintf(s,"%s_dec.txt", prefix);
fdec = fopen(s, "wt");
assert(fdec != NULL);
}
for(i=0; i<320/5; i++)
fprintf(fdec,"%f\t",Fw[i].real);
fprintf(fdec,"\n");
}
void dump_bg(float e, float bg_est, float percent_uv) {
char s[MAX_STR];
if (!dumpon) return;
if (fbg == NULL) {
sprintf(s,"%s_bg.txt", prefix);
fbg = fopen(s, "wt");
assert(fbg != NULL);
}
fprintf(fbg,"%f\t%f\t%f\n", e, bg_est, percent_uv);
}
void dump_E(float E) {
char s[MAX_STR];
if (!dumpon) return;
if (fE == NULL) {
sprintf(s,"%s_E.txt", prefix);
fE = fopen(s, "wt");
assert(fE != NULL);
}
fprintf(fE,"%f\n", 10.0*log10(E));
}
#if 0
void dump_Rk(float Rk[]) {
int i;
char s[MAX_STR];
if (!dumpon) return;
if (frk == NULL) {
sprintf(s,"%s_rk.txt", prefix);
frk = fopen(s, "wt");
assert(frk != NULL);
}
for(i=0; i<P_MAX; i++)
fprintf(frk,"%f\t",Rk[i]);
fprintf(frk,"\n");
}
#endif
#endif
+82
View File
@@ -0,0 +1,82 @@
/*---------------------------------------------------------------------------*\
FILE........: dump.h
AUTHOR......: David Rowe
DATE CREATED: 25/8/09
Routines to dump data to text files for Octave analysis.
\*---------------------------------------------------------------------------*/
/*
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __DUMP__
#define __DUMP__
#include "defines.h"
#include "comp.h"
#include "codec2_fft.h"
#include "codec2_internal.h"
void dump_on(char filename_prefix[]);
void dump_off();
void dump_Sn(int m_pitch, float Sn[]);
void dump_Sw(COMP Sw[]);
void dump_Sw_(COMP Sw_[]);
void dump_Ew(COMP Ew[]);
void dump_softdec(float *softdec, int n);
/* amplitude modelling */
void dump_model(MODEL *m);
void dump_quantised_model(MODEL *m);
void dump_Pwn(COMP Pw[]);
void dump_Pw(float Pw[]);
void dump_Rw(float Rw[]);
void dump_lsp(float lsp[]);
void dump_weights(float w[], int ndim);
void dump_lsp_(float lsp_[]);
void dump_mel(float mel[], int order);
void dump_mel_indexes(int mel_indexes[], int order);
void dump_ak(float ak[], int order);
void dump_ak_(float ak[], int order);
void dump_E(float E);
void dump_lpc_snr(float snr);
/* phase modelling */
void dump_snr(float snr);
void dump_phase(float phase[], int L);
void dump_phase_(float phase[], int L);
void dump_hephase(int ind[], int dim);
/* NLP states */
void dump_sq(int m_pitch, float sq[]);
void dump_dec(COMP Fw[]);
void dump_Fw(COMP Fw[]);
void dump_e(float e_hz[]);
#if 0
void dump_Rk(float Rk[]);
#endif
/* post filter */
void dump_bg(float e, float bg_est, float percent_uv);
void dump_Pwb(float Pwb[]);
#endif
+192
View File
@@ -0,0 +1,192 @@
/*---------------------------------------------------------------------------*\
FILE........: fdmdv_internal.h
AUTHOR......: David Rowe
DATE CREATED: April 16 2012
Header file for FDMDV internal functions, exposed via this header
file for testing.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2012 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FDMDV_INTERNAL__
#define __FDMDV_INTERNAL__
#include "comp.h"
#include "codec2_fdmdv.h"
#include "codec2_fft.h"
/*---------------------------------------------------------------------------*\
DEFINES
\*---------------------------------------------------------------------------*/
#ifndef PI
#define PI 3.141592654
#endif
#define FS 8000 /* sample rate in Hz */
#define T (1.0/FS) /* sample period in seconds */
#define RS 50 /* symbol rate in Hz */
#define NC 20 /* max number of data carriers (plus one pilot in the centre) */
#define NB 2 /* Bits/symbol for QPSK modulation */
#define RB (NC*RS*NB) /* bit rate */
#define M_FAC (FS/RS) /* oversampling factor */
#define NSYM 6 /* number of symbols to filter over */
#define NFILTER (NSYM*M_FAC) /* size of tx/rx filters at sample rate M */
#define FSEP 75 /* Default separation between carriers (Hz) */
#define NT 5 /* number of symbols we estimate timing over */
#define P 4 /* oversample factor used for initial rx symbol filtering output */
#define Q (M_FAC/4) /* oversample factor used for initial rx symbol filtering input */
#define NRXDEC 31 /* number of taps in the rx decimation filter */
#define NPILOT_LUT (4*M_FAC) /* number of pilot look up table samples */
#define NPILOTCOEFF 30 /* number of FIR filter coeffs in LP filter */
#define NPILOTBASEBAND (NPILOTCOEFF+M_FAC+M_FAC/P) /* number of pilot baseband samples reqd for pilot LPF */
#define NPILOTLPF (4*M_FAC) /* number of samples we DFT pilot over, pilot est window */
#define MPILOTFFT 256
#define NSYNC_MEM 6
/* averaging filter coeffs */
#define TRACK_COEFF 0.5
#define SNR_COEFF 0.9 /* SNR est averaging filter coeff */
/*---------------------------------------------------------------------------*\
STRUCT for States
\*---------------------------------------------------------------------------*/
struct FDMDV {
int Nc;
float fsep;
/* test data (test frame) states */
int ntest_bits;
int current_test_bit;
int *rx_test_bits_mem;
/* Modulator */
int old_qpsk_mapping;
int tx_pilot_bit;
COMP prev_tx_symbols[NC+1];
COMP tx_filter_memory[NC+1][NSYM];
COMP phase_tx[NC+1];
COMP freq[NC+1];
float freq_pol[NC+1];
/* Pilot generation at demodulator */
COMP pilot_lut[NPILOT_LUT];
int pilot_lut_index;
int prev_pilot_lut_index;
/* freq offset estimation states */
codec2_fft_cfg fft_pilot_cfg;
COMP pilot_baseband1[NPILOTBASEBAND];
COMP pilot_baseband2[NPILOTBASEBAND];
COMP pilot_lpf1[NPILOTLPF];
COMP pilot_lpf2[NPILOTLPF];
COMP S1[MPILOTFFT];
COMP S2[MPILOTFFT];
/* baseband to low IF carrier states */
COMP fbb_rect;
float fbb_pol;
COMP fbb_phase_tx;
COMP fbb_phase_rx;
/* freq offset correction states */
float foff;
COMP foff_phase_rect;
float foff_filt;
/* Demodulator */
COMP rxdec_lpf_mem[NRXDEC-1+M_FAC];
COMP rx_fdm_mem[NFILTER+M_FAC];
COMP phase_rx[NC+1];
COMP rx_filter_mem_timing[NC+1][NT*P];
float rx_timing;
COMP phase_difference[NC+1];
COMP prev_rx_symbols[NC+1];
/* sync state machine */
int sync_mem[NSYNC_MEM];
int fest_state;
int sync;
int timer;
/* SNR estimation states */
float sig_est[NC+1];
float noise_est[NC+1];
/* channel simulation */
float sig_pwr_av;
};
/*---------------------------------------------------------------------------*\
FUNCTION PROTOTYPES
\*---------------------------------------------------------------------------*/
void bits_to_dqpsk_symbols(COMP tx_symbols[], int Nc, COMP prev_tx_symbols[], int tx_bits[], int *pilot_bit, int old_qpsk_mapping);
void tx_filter(COMP tx_baseband[NC+1][M_FAC], int Nc, COMP tx_symbols[], COMP tx_filter_memory[NC+1][NSYM]);
void fdm_upconvert(COMP tx_fdm[], int Nc, COMP tx_baseband[NC+1][M_FAC], COMP phase_tx[], COMP freq_tx[],
COMP *fbb_phase, COMP fbb_rect);
void tx_filter_and_upconvert(COMP tx_fdm[], int Nc, COMP tx_symbols[],
COMP tx_filter_memory[NC+1][NSYM],
COMP phase_tx[], COMP freq[], COMP *fbb_phase, COMP fbb_rect);
void generate_pilot_fdm(COMP *pilot_fdm, int *bit, float *symbol, float *filter_mem, COMP *phase, COMP *freq);
void generate_pilot_lut(COMP pilot_lut[], COMP *pilot_freq);
float rx_est_freq_offset(struct FDMDV *f, COMP rx_fdm[], int nin, int do_fft);
void lpf_peak_pick(float *foff, float *max, COMP pilot_baseband[], COMP pilot_lpf[], codec2_fft_cfg fft_pilot_cfg, COMP S[], int nin, int do_fft);
void fdm_downconvert(COMP rx_baseband[NC+1][M_FAC+M_FAC/P], int Nc, COMP rx_fdm[], COMP phase_rx[], COMP freq[], int nin);
void rxdec_filter(COMP rx_fdm_filter[], COMP rx_fdm[], COMP rxdec_lpf_mem[], int nin);
void rx_filter(COMP rx_filt[NC+1][P+1], int Nc, COMP rx_baseband[NC+1][M_FAC+M_FAC/P], COMP rx_filter_memory[NC+1][NFILTER], int nin);
void down_convert_and_rx_filter(COMP rx_filt[NC+1][P+1], int Nc, COMP rx_fdm[],
COMP rx_fdm_mem[], COMP phase_rx[], COMP freq[],
float freq_pol[], int nin, int dec_rate);
float rx_est_timing(COMP rx_symbols[], int Nc,
COMP rx_filt[NC+1][P+1],
COMP rx_filter_mem_timing[NC+1][NT*P],
float env[],
int nin,
int m);
float qpsk_to_bits(int rx_bits[], int *sync_bit, int Nc, COMP phase_difference[], COMP prev_rx_symbols[], COMP rx_symbols[], int old_qpsk_mapping);
void snr_update(float sig_est[], float noise_est[], int Nc, COMP phase_difference[]);
int freq_state(int *reliable_sync_bit, int sync_bit, int *state, int *timer, int *sync_mem);
float calc_snr(int Nc, float sig_est[], float noise_est[]);
#endif
+413
View File
@@ -0,0 +1,413 @@
/* Generated by fm_fir_coeff_file() Octave function in fm.m */
const float bin[]={
4.79309e-05,
1.1306e-05,
-5.5983e-05,
-7.01194e-05,
7.06484e-06,
9.92193e-05,
8.58591e-05,
-4.54326e-05,
-0.000152003,
-8.65645e-05,
0.000107704,
0.000207915,
6.24307e-05,
-0.000194905,
-0.000256788,
-3.72067e-06,
0.000303862,
0.000285027,
-9.75377e-05,
-0.000426141,
-0.000276571,
0.000245596,
0.00054748,
0.000214543,
-0.000438995,
-0.000647904,
-8.35097e-05,
0.000668808,
0.000702715,
-0.000127804,
-0.000917433,
-0.000684399,
0.000423605,
0.00115821,
0.000565432,
-0.000798262,
-0.00135608,
-0.000321829,
0.00123404,
0.00146953,
-6.28411e-05,
-0.00169975,
-0.00145365,
0.000593351,
0.00215057,
0.00126444,
-0.00125906,
-0.00252937,
-0.000863858,
0.00203097,
0.00276961,
0.000225378,
-0.00286002,
-0.00279968,
0.00066048,
0.00367697,
0.00254856,
-0.00178121,
-0.00439398,
-0.00195226,
0.00309842,
0.00490791,
0.000960678,
-0.0045454,
-0.00510509,
0.000456067,
0.00602631,
0.00486678,
-0.00230217,
-0.00741688,
-0.00407467,
0.00455244,
0.00856596,
0.0026148,
-0.00715072,
-0.0092966,
-0.000377815,
0.0100109,
0.00940383,
-0.00274808,
-0.0130204,
-0.00864357,
0.00689875,
0.0160465,
0.0066998,
-0.0122874,
-0.0189444,
-0.0030966,
0.0193367,
0.0215669,
-0.00304913,
-0.0290487,
-0.0237748,
0.0138493,
0.0443198,
0.0254471,
-0.0364426,
-0.0771407,
-0.0264901,
0.120993,
0.285249,
0.366844,
0.285249,
0.120993,
-0.0264901,
-0.0771407,
-0.0364426,
0.0254471,
0.0443198,
0.0138493,
-0.0237748,
-0.0290487,
-0.00304913,
0.0215669,
0.0193367,
-0.0030966,
-0.0189444,
-0.0122874,
0.0066998,
0.0160465,
0.00689875,
-0.00864357,
-0.0130204,
-0.00274808,
0.00940383,
0.0100109,
-0.000377815,
-0.0092966,
-0.00715072,
0.0026148,
0.00856596,
0.00455244,
-0.00407467,
-0.00741688,
-0.00230217,
0.00486678,
0.00602631,
0.000456067,
-0.00510509,
-0.0045454,
0.000960678,
0.00490791,
0.00309842,
-0.00195226,
-0.00439398,
-0.00178121,
0.00254856,
0.00367697,
0.00066048,
-0.00279968,
-0.00286002,
0.000225378,
0.00276961,
0.00203097,
-0.000863858,
-0.00252937,
-0.00125906,
0.00126444,
0.00215057,
0.000593351,
-0.00145365,
-0.00169975,
-6.28411e-05,
0.00146953,
0.00123404,
-0.000321829,
-0.00135608,
-0.000798262,
0.000565432,
0.00115821,
0.000423605,
-0.000684399,
-0.000917433,
-0.000127804,
0.000702715,
0.000668808,
-8.35097e-05,
-0.000647904,
-0.000438995,
0.000214543,
0.00054748,
0.000245596,
-0.000276571,
-0.000426141,
-9.75377e-05,
0.000285027,
0.000303862,
-3.72067e-06,
-0.000256788,
-0.000194905,
6.24307e-05,
0.000207915,
0.000107704,
-8.65645e-05,
-0.000152003,
-4.54326e-05,
8.58591e-05,
9.92193e-05,
7.06484e-06,
-7.01194e-05,
-5.5983e-05,
1.1306e-05,
4.79309e-05
};
const float bout[]={
-0.000901664,
-0.00105423,
-0.00102202,
-0.000796428,
-0.0004047,
9.24929e-05,
0.000610043,
0.00105267,
0.00133217,
0.00138452,
0.00118367,
0.000749102,
0.000145346,
-0.000527025,
-0.00114777,
-0.00159812,
-0.00178311,
-0.00165083,
-0.00120494,
-0.000507584,
0.000328412,
0.0011573,
0.00182538,
0.00219909,
0.00219097,
0.00177877,
0.00101358,
1.48175e-05,
-0.00104765,
-0.00198192,
-0.00260813,
-0.00279243,
-0.00247437,
-0.00168247,
-0.000534171,
0.000780521,
0.00202976,
0.00298006,
0.00343915,
0.00329371,
0.00253482,
0.00126569,
-0.000310763,
-0.00192329,
-0.00327808,
-0.0041113,
-0.00423916,
-0.00359628,
-0.00225463,
-0.000418452,
0.00160526,
0.00345676,
0.00478613,
0.00531776,
0.00490513,
0.00356541,
0.00148629,
-0.000997692,
-0.00345694,
-0.0054391,
-0.00654985,
-0.00652835,
-0.00530323,
-0.00301796,
-1.90046e-05,
0.00319335,
0.00604515,
0.00798756,
0.00859787,
0.00766479,
0.00524199,
0.001658,
-0.00252213,
-0.00658004,
-0.00976079,
-0.011405,
-0.0110744,
-0.00864874,
-0.00437487,
0.00114403,
0.00702171,
0.0122173,
0.0157018,
0.0166372,
0.0145415,
0.00940928,
0.00176699,
-0.00735151,
-0.0165112,
-0.0240533,
-0.0283208,
-0.027902,
-0.0218568,
-0.00988994,
0.0075553,
0.0293009,
0.0535398,
0.0780316,
0.100365,
0.118251,
0.129808,
0.143804,
0.129808,
0.118251,
0.100365,
0.0780316,
0.0535398,
0.0293009,
0.0075553,
-0.00988994,
-0.0218568,
-0.027902,
-0.0283208,
-0.0240533,
-0.0165112,
-0.00735151,
0.00176699,
0.00940928,
0.0145415,
0.0166372,
0.0157018,
0.0122173,
0.00702171,
0.00114403,
-0.00437487,
-0.00864874,
-0.0110744,
-0.011405,
-0.00976079,
-0.00658004,
-0.00252213,
0.001658,
0.00524199,
0.00766479,
0.00859787,
0.00798756,
0.00604515,
0.00319335,
-1.90046e-05,
-0.00301796,
-0.00530323,
-0.00652835,
-0.00654985,
-0.0054391,
-0.00345694,
-0.000997692,
0.00148629,
0.00356541,
0.00490513,
0.00531776,
0.00478613,
0.00345676,
0.00160526,
-0.000418452,
-0.00225463,
-0.00359628,
-0.00423916,
-0.0041113,
-0.00327808,
-0.00192329,
-0.000310763,
0.00126569,
0.00253482,
0.00329371,
0.00343915,
0.00298006,
0.00202976,
0.000780521,
-0.000534171,
-0.00168247,
-0.00247437,
-0.00279243,
-0.00260813,
-0.00198192,
-0.00104765,
1.48175e-05,
0.00101358,
0.00177877,
0.00219097,
0.00219909,
0.00182538,
0.0011573,
0.000328412,
-0.000507584,
-0.00120494,
-0.00165083,
-0.00178311,
-0.00159812,
-0.00114777,
-0.000527025,
0.000145346,
0.000749102,
0.00118367,
0.00138452,
0.00133217,
0.00105267,
0.000610043,
9.24929e-05,
-0.0004047,
-0.000796428,
-0.00102202,
-0.00105423,
-0.000901664
};
+110
View File
@@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------*\
FILE........: fmfsk.h
AUTHOR......: Brady O'Brien
DATE CREATED: 6 February 2016
C Implementation of 2FSK+Manchester over FM modulator/demodulator, based
on mancyfsk.m and fmfsk.m
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2016 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __C2FMFSK_H
#define __C2FMFSK_H
#include <stdint.h>
#include "comp.h"
#include "modem_stats.h"
#define FMFSK_SCALE 16383
/*
* fm-me-2fsk state
*/
struct FMFSK{
/* Static fmfsk parameters */
int Rb; /* Manchester-encoded bitrate */
int Rs; /* Raw modem symbol rate */
int Fs; /* Sample rate */
int Ts; /* Samples-per-symbol */
int N; /* Sample processing buffer size */
int nsym; /* Number of raw modem symbols processed per demod call */
int nbit; /* Number of bits spit out per demod call */
int nmem; /* Number of samples kept around between demod calls */
/* State kept by demod */
int nin; /* Number of samples to be demod-ed the next cycle */
int lodd; /* Last integrated sample for odd bitstream generation */
float * oldsamps; /* Memory of old samples to make clock-offset-tolerance possible */
/* Stats generated by demod */
float norm_rx_timing; /* RX Timing, used to calculate clock offset */
int ppm; /* Clock offset in parts-per-million */
float snr_mean;
/* Modem stat structure */
struct MODEM_STATS * stats;
};
/*
* Create a new fmfsk modem instance.
*
* int Fs - sample rate
* int Rb - non-manchester bitrate
* returns - new struct FMFSK on sucess, NULL on failure
*/
struct FMFSK * fmfsk_create(int Fs,int Rb);
/*
* Destroys an fmfsk modem and deallocates memory
*/
void fmfsk_destroy(struct FMFSK *fmfsk);
/*
* Deposit demod statistics into a MODEM_STATS struct
*/
void fmfsk_get_demod_stats(struct FMFSK *fmfsk,struct MODEM_STATS *stats);
/*
* Returns the number of samples that must be fed to fmfsk_demod the next
* cycle
*/
uint32_t fmfsk_nin(struct FMFSK *fmfsk);
/*
* Modulates nbit bits into N samples to be sent through an FM radio
*
* struct FSK *fsk - FSK config/state struct, set up by fsk_create
* float mod_out[] - Buffer for N samples of modulated FMFSK
* uint8_t tx_bits[] - Buffer containing Nbits unpacked bits
*/
void fmfsk_mod(struct FMFSK *fmfsk, float fmfsk_out[],uint8_t bits_in[]);
/*
* Demodulate some number of FMFSK samples. The number of samples to be
* demodulated can be found by calling fmfsk_nin().
*
* struct FMFSK *fsk - FMFSK config/state struct, set up by fsk_create
* uint8_t rx_bits[] - Buffer for nbit unpacked bits to be written
* float fsk_in[] - nin samples of modualted FMFSK from an FM radio
*/
void fmfsk_demod(struct FMFSK *fmfsk, uint8_t rx_bits[],float fmfsk_in[]);
#endif
+142
View File
@@ -0,0 +1,142 @@
/*---------------------------------------------------------------------------*\
FILE........: freedv_api.h
AUTHOR......: David Rowe
DATE CREATED: August 2014
Library of API functions that implement FreeDV "modes", useful for
embedding FreeDV in other programs. Please see the documentation
for each function in freedv_api.c, and the sample freedv_tx.c and
freedv_rx.c programs.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __FREEDV__
// This declares a single-precision (float) complex number
#include <sys/types.h>
#include "comp.h"
#define FREEDV_MODE_1600 0
#define FREEDV_MODE_700 1
#define FREEDV_MODE_700B 2
#define FREEDV_MODE_2400A 3
#define FREEDV_MODE_2400B 4
#define FREEDV_MODE_800XA 5
#define FREEDV_MODE_700C 6
struct freedv;
/* Called when text message char is decoded */
typedef void (*freedv_callback_rx)(void *, char);
/* Called when new text message char is needed */
typedef char (*freedv_callback_tx)(void *);
typedef void (*freedv_calback_error_pattern)
(void *error_pattern_callback_state, short error_pattern[], int sz_error_pattern);
/* Protocol bits are packed MSB-first */
/* Called when a frame containing protocol data is decoded */
typedef void (*freedv_callback_protorx)(void *, char *);
/* Called when a frame containing protocol data is to be sent */
typedef void (*freedv_callback_prototx)(void *, char *);
/* Data packet callbacks */
/* Called when a packet has been received */
typedef void (*freedv_callback_datarx)(void *, unsigned char *packet, size_t size);
/* Called when a new packet can be send */
typedef void (*freedv_callback_datatx)(void *, unsigned char *packet, size_t *size);
/*---------------------------------------------------------------------------*\
FreeDV API functions
\*---------------------------------------------------------------------------*/
// open, close ----------------------------------------------------------------
struct freedv *freedv_open(int mode);
void freedv_close (struct freedv *freedv);
// Transmit -------------------------------------------------------------------
void freedv_tx (struct freedv *freedv, short mod_out[], short speech_in[]);
void freedv_comptx (struct freedv *freedv, COMP mod_out[], short speech_in[]);
void freedv_codectx (struct freedv *f, short mod_out[], unsigned char *packed_codec_bits);
void freedv_datatx (struct freedv *f, short mod_out[]);
int freedv_data_ntxframes (struct freedv *freedv);
// Receive -------------------------------------------------------------------
int freedv_nin (struct freedv *freedv);
int freedv_rx (struct freedv *freedv, short speech_out[], short demod_in[]);
int freedv_floatrx (struct freedv *freedv, short speech_out[], float demod_in[]);
int freedv_comprx (struct freedv *freedv, short speech_out[], COMP demod_in[]);
int freedv_codecrx (struct freedv *freedv, unsigned char *packed_codec_bits, short demod_in[]);
// Set parameters ------------------------------------------------------------
void freedv_set_callback_txt (struct freedv *freedv, freedv_callback_rx rx, freedv_callback_tx tx, void *callback_state);
void freedv_set_callback_protocol (struct freedv *freedv, freedv_callback_protorx rx, freedv_callback_prototx tx, void *callback_state);
void freedv_set_callback_data (struct freedv *freedv, freedv_callback_datarx datarx, freedv_callback_datatx datatx, void *callback_state);
void freedv_set_test_frames (struct freedv *freedv, int test_frames);
void freedv_set_test_frames_diversity (struct freedv *freedv, int test_frames_diversity);
void freedv_set_smooth_symbols (struct freedv *freedv, int smooth_symbols);
void freedv_set_squelch_en (struct freedv *freedv, int squelch_en);
void freedv_set_snr_squelch_thresh (struct freedv *freedv, float snr_squelch_thresh);
void freedv_set_clip (struct freedv *freedv, int val);
void freedv_set_total_bit_errors (struct freedv *freedv, int val);
void freedv_set_total_bits (struct freedv *freedv, int val);
void freedv_set_callback_error_pattern (struct freedv *freedv, freedv_calback_error_pattern cb, void *state);
void freedv_set_varicode_code_num (struct freedv *freedv, int val);
void freedv_set_data_header (struct freedv *freedv, unsigned char *header);
int freedv_set_alt_modem_samp_rate (struct freedv *freedv, int samp_rate);
void freedv_set_carrier_ampl (struct freedv *freedv, int c, float ampl);
// Get parameters -------------------------------------------------------------------------
struct MODEM_STATS;
int freedv_get_version(void);
int freedv_get_mode (struct freedv *freedv);
void freedv_get_modem_stats (struct freedv *freedv, int *sync, float *snr_est);
void freedv_get_modem_extended_stats(struct freedv *freedv, struct MODEM_STATS *stats);
int freedv_get_test_frames (struct freedv *freedv);
int freedv_get_n_speech_samples (struct freedv *freedv);
int freedv_get_modem_sample_rate (struct freedv *freedv);
int freedv_get_n_max_modem_samples (struct freedv *freedv);
int freedv_get_n_nom_modem_samples (struct freedv *freedv);
int freedv_get_total_bits (struct freedv *freedv);
int freedv_get_total_bit_errors (struct freedv *freedv);
int freedv_get_sync (struct freedv *freedv);
struct FSK * freedv_get_fsk(struct freedv *f);
struct CODEC2 *freedv_get_codec2 (struct freedv *freedv);
int freedv_get_n_codec_bits (struct freedv *freedv);
int freedv_get_sz_error_pattern (struct freedv *freedv);
int freedv_get_protocol_bits (struct freedv *freedv);
#endif
#ifdef __cplusplus
}
#endif
+241
View File
@@ -0,0 +1,241 @@
/*---------------------------------------------------------------------------*\
FILE........: freedv_api_internal.h
AUTHOR......: David Rowe
DATE CREATED: August 2014
This declares the structure freedv. A pointer to this structure is
returned by the FreeDV API freedv_open() function. The pointer is used
by the other FreeDV API functions declared in freedv_api.h. This
structure is intended to be internal to the FreeDV API. The public
functions are declared in freedv_api.h. Changes to this structure
are expected. Changes (except additions) to freedv_api.h are
discouraged.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __FREEDV__
#include "varicode.h"
#include "fsk.h"
#include "fmfsk.h"
#include "codec2_fdmdv.h"
#include "codec2_cohpsk.h"
struct quisk_cfFilter { // Structure to hold the static data for FIR filters
float * dCoefs; // filter coefficients
int nBuf; // dimension of cBuf
int nTaps; // dimension of dSamples, cSamples, dCoefs
int decim_index; // index of next sample for decimation
COMP * cSamples; // storage for old samples
COMP * ptcSamp; // next available position in cSamples
COMP * cBuf; // auxillary buffer for interpolation
} ;
static int quisk_cfInterpDecim(COMP *, int, struct quisk_cfFilter *, int, int);
static void quisk_filt_cfInit(struct quisk_cfFilter *, float *, int);
static void quisk_filt_destroy(struct quisk_cfFilter *);
static float quiskFilt120t480[480];
struct freedv {
int mode;
struct CODEC2 *codec2;
struct FDMDV *fdmdv;
struct MODEM_STATS stats;
struct COHPSK *cohpsk;
struct FSK *fsk;
struct FMFSK *fmfsk;
struct freedv_vhf_deframer * deframer; //Extracts frames from VHF stream
struct quisk_cfFilter * ptFilter7500to8000; // Filters to change to/from 7500 and 8000 sps
struct quisk_cfFilter * ptFilter8000to7500;
int n_speech_samples;
int n_nom_modem_samples; // size of tx and most rx modem sample buffers
int n_max_modem_samples; // make your rx modem sample buffers this big
int n_nat_modem_samples; // tx modem sample block length as used by the modem before interpolation to output
int modem_sample_rate; // ATM caller is responsible for meeting this (TBC)
int clip; // non-zero for cohpsk modem output clipping for low PAPR
unsigned char *packed_codec_bits;
int *codec_bits;
int *tx_bits;
int *fdmdv_bits;
int *rx_bits;
int tx_sync_bit;
int smooth_symbols;
float *prev_rx_bits;
int n_codec_bits; // amount of codec bits in a frame
int *ptest_bits_coh;
int *ptest_bits_coh_end;
int test_frames; // set this baby for 1 to tx/rx test frames to look at bit error stats
int test_frames_diversity; // 1 -> used combined carriers for error counting on 700 waveforms
int test_frame_sync_state;
int test_frame_sync_state_upper; // when test_frames_diveristy==0 we need extra states for upper carriers
int test_frame_count;
int total_bits;
int total_bit_errors;
int sz_error_pattern;
/* optional user defined function to pass error pattern when a test frame is received */
void *error_pattern_callback_state;
void (*freedv_put_error_pattern)(void *error_pattern_callback_state, short error_pattern[], int sz_error_pattern);
int sync;
int evenframe;
float snr_est;
float snr_squelch_thresh;
int squelch_en;
int nin;
struct VARICODE_DEC varicode_dec_states;
short tx_varicode_bits[VARICODE_MAX_BITS];
int nvaricode_bits;
int varicode_bit_index;
/* user defined function ptrs to produce and consume ASCII
characters using aux txt channel */
char (*freedv_get_next_tx_char)(void *callback_state);
void (*freedv_put_next_rx_char)(void *callback_state, char c);
void *callback_state;
/* user defined functions to produce and consume protocol bits */
/* Protocol bits are packed MSB-first */
void (*freedv_put_next_proto)(void *callback_state, char *proto_bits_packed);
void (*freedv_get_next_proto)(void *callback_state, char *proto_bits_packed);
void *proto_callback_state;
int n_protocol_bits;
};
// FIR filter suitable for changing rates 7500 to/from 8000
// Sample 120000 Hz, pass 2700, stop 3730, ripple 0.1dB, atten 100 dB. Stop 0.03108.
static float quiskFilt120t480[480] = { -0.000005050567303837, -0.000000267011791999, 0.000000197734700398, 0.000001038946634000,
0.000002322193058869, 0.000004115682735322, 0.000006499942123311, 0.000009551098482930, 0.000013350669444763,
0.000017966192635412, 0.000023463361155584, 0.000029885221425020, 0.000037271082107518, 0.000045630720487935,
0.000054970017069384, 0.000065233162392019, 0.000076360900545177, 0.000088271373315159, 0.000100818605854714,
0.000113853476544409, 0.000127174196746337, 0.000140558396336177, 0.000153744508371709, 0.000166450784469067,
0.000178368313347299, 0.000189176709991702, 0.000198541881389953, 0.000206128795372885, 0.000211604878787747,
0.000214655997661182, 0.000214994859281552, 0.000212358734245594, 0.000206539880117977, 0.000197379393194548,
0.000184780318878738, 0.000168719942655099, 0.000149250512353807, 0.000126511346757621, 0.000100726393185629,
0.000072210925236429, 0.000041365841965015, 0.000008680571408025, -0.000025277165852799, -0.000059865389594949,
-0.000094384355854646, -0.000128080670195777, -0.000160170174848483, -0.000189854272533545, -0.000216333899003825,
-0.000238836419299503, -0.000256632149501508, -0.000269058714331757, -0.000275541485292432, -0.000275614059005332,
-0.000268937472718753, -0.000255317038867589, -0.000234717772155001, -0.000207273956099563, -0.000173297342436372,
-0.000133280012107173, -0.000087895370243821, -0.000037986085678081, 0.000015440388211825, 0.000071232572821451,
0.000128114399130489, 0.000184710477990398, 0.000239577162514028, 0.000291234779803098, 0.000338204791740229,
0.000379047713684221, 0.000412403761615261, 0.000437031818051652, 0.000451848709179591, 0.000455966225408344,
0.000448726371643413, 0.000429729020814434, 0.000398857326863837, 0.000356297600912998, 0.000302547334727027,
0.000238422248479072, 0.000165048886226905, 0.000083853091464077, -0.000003462782744354, -0.000094949813106744,
-0.000188451833293202, -0.000281651282503015, -0.000372121907291206, -0.000457387566635848, -0.000534985542936898,
-0.000602532044011899, -0.000657788245032425, -0.000698728981427767, -0.000723604675185869, -0.000731002305621048,
-0.000719899536922384, -0.000689709694056092, -0.000640319946685634, -0.000572115873292030, -0.000485996080304965,
-0.000383371840261246, -0.000266155252511831, -0.000136731311264191, 0.000002082667095075, 0.000147092077716480,
0.000294790953130229, 0.000441441918072383, 0.000583164190168290, 0.000716029226064227, 0.000836164238172957,
0.000939856052624227, 0.001023657909064450, 0.001084492755093968, 0.001119751426837743, 0.001127383039339373,
0.001105974243787613, 0.001054815583369999, 0.000973950761085690, 0.000864209315714227, 0.000727219011746881,
0.000565398080608305, 0.000381924396468366, 0.000180685902835315, -0.000033793183292569, -0.000256444114966522,
-0.000481764526566339, -0.000703946352348464, -0.000917016099829735, -0.001114986581270253, -0.001292014799874503,
-0.001442563411804926, -0.001561559957317790, -0.001644551048567398, -0.001687846581475964, -0.001688649703502788,
-0.001645167889846890, -0.001556702802350076, -0.001423714708648073, -0.001247857669697092, -0.001031986722557201,
-0.000780131048444402, -0.000497436825078657, -0.000190077210351809, 0.000134868279325909, 0.000469563533327739,
0.000805591531546815, 0.001134152328775355, 0.001446279849797673, 0.001733071409562941, 0.001985924997799762,
0.002196778054604388, 0.002358342626407065, 0.002464328098407475, 0.002509648218888532, 0.002490604086803692,
0.002405037734357425, 0.002252452724297770, 0.002034094661603120, 0.001752990365583534, 0.001413941154886139,
0.001023470495638453, 0.000589723521647734, 0.000122320866350319, -0.000367832138027160, -0.000868777013398284,
-0.001367771151677059, -0.001851587344265625, -0.002306838088978190, -0.002720317947026380, -0.003079353614002113,
-0.003372155891804708, -0.003588162376578369, -0.003718362558663737, -0.003755596511143005, -0.003694818131674599,
-0.003533315298404129, -0.003270878754553819, -0.002909914962857412, -0.002455496391464944, -0.001915346645364514,
-0.001299757227227888, -0.000621437066532776, 0.000104706515738248, 0.000861849931067767, 0.001631595707499856,
0.002394368911341672, 0.003129858565588139, 0.003817496679992245, 0.004436963307209760, 0.004968707287606522,
0.005394469536085115, 0.005697797543539088, 0.005864537618023589, 0.005883292537600076, 0.005745832319314692,
0.005447447099071761, 0.004987231255534477, 0.004368289529377007, 0.003597859022418248, 0.002687338851256991,
0.001652226293162047, 0.000511956075882180, -0.000710356149138656, -0.001988263330091648, -0.003292424566049982,
-0.004591123342747130, -0.005850857852106148, -0.007036991266043732, -0.008114450164977267, -0.009048456200082230,
-0.009805276478965942, -0.010352975302354198, -0.010662152577592631, -0.010706650669328861, -0.010464214075017983,
-0.009917087295446811, -0.009052534679222271, -0.007863270920348924, -0.006347789704693751, -0.004510582323649121,
-0.002362238055733795, 0.000080576968834213, 0.002795265196543707, 0.005753566158586979, 0.008921944932552510,
0.012262093950265378, 0.015731539846483594, 0.019284344624007944, 0.022871886384520687, 0.026443706729191677,
0.029948406200633094, 0.033334570666910354, 0.036551709955124537, 0.039551189200810140, 0.042287133974308874,
0.044717290029466283, 0.046803820535016104, 0.048514022996355009, 0.049820951883635139, 0.050703932928426454,
0.051148959210315710, 0.051148959210315710, 0.050703932928426454, 0.049820951883635139, 0.048514022996355009,
0.046803820535016104, 0.044717290029466283, 0.042287133974308874, 0.039551189200810140, 0.036551709955124537,
0.033334570666910354, 0.029948406200633094, 0.026443706729191677, 0.022871886384520687, 0.019284344624007944,
0.015731539846483594, 0.012262093950265378, 0.008921944932552510, 0.005753566158586979, 0.002795265196543707,
0.000080576968834213, -0.002362238055733795, -0.004510582323649121, -0.006347789704693751, -0.007863270920348924,
-0.009052534679222271, -0.009917087295446811, -0.010464214075017983, -0.010706650669328861, -0.010662152577592631,
-0.010352975302354198, -0.009805276478965942, -0.009048456200082230, -0.008114450164977267, -0.007036991266043732,
-0.005850857852106148, -0.004591123342747130, -0.003292424566049982, -0.001988263330091648, -0.000710356149138656,
0.000511956075882180, 0.001652226293162047, 0.002687338851256991, 0.003597859022418248, 0.004368289529377007,
0.004987231255534477, 0.005447447099071761, 0.005745832319314692, 0.005883292537600076, 0.005864537618023589,
0.005697797543539088, 0.005394469536085115, 0.004968707287606522, 0.004436963307209760, 0.003817496679992245,
0.003129858565588139, 0.002394368911341672, 0.001631595707499856, 0.000861849931067767, 0.000104706515738248,
-0.000621437066532776, -0.001299757227227888, -0.001915346645364514, -0.002455496391464944, -0.002909914962857412,
-0.003270878754553819, -0.003533315298404129, -0.003694818131674599, -0.003755596511143005, -0.003718362558663737,
-0.003588162376578369, -0.003372155891804708, -0.003079353614002113, -0.002720317947026380, -0.002306838088978190,
-0.001851587344265625, -0.001367771151677059, -0.000868777013398284, -0.000367832138027160, 0.000122320866350319,
0.000589723521647734, 0.001023470495638453, 0.001413941154886139, 0.001752990365583534, 0.002034094661603120,
0.002252452724297770, 0.002405037734357425, 0.002490604086803692, 0.002509648218888532, 0.002464328098407475,
0.002358342626407065, 0.002196778054604388, 0.001985924997799762, 0.001733071409562941, 0.001446279849797673,
0.001134152328775355, 0.000805591531546815, 0.000469563533327739, 0.000134868279325909, -0.000190077210351809,
-0.000497436825078657, -0.000780131048444402, -0.001031986722557201, -0.001247857669697092, -0.001423714708648073,
-0.001556702802350076, -0.001645167889846890, -0.001688649703502788, -0.001687846581475964, -0.001644551048567398,
-0.001561559957317790, -0.001442563411804926, -0.001292014799874503, -0.001114986581270253, -0.000917016099829735,
-0.000703946352348464, -0.000481764526566339, -0.000256444114966522, -0.000033793183292569, 0.000180685902835315,
0.000381924396468366, 0.000565398080608305, 0.000727219011746881, 0.000864209315714227, 0.000973950761085690,
0.001054815583369999, 0.001105974243787613, 0.001127383039339373, 0.001119751426837743, 0.001084492755093968,
0.001023657909064450, 0.000939856052624227, 0.000836164238172957, 0.000716029226064227, 0.000583164190168290,
0.000441441918072383, 0.000294790953130229, 0.000147092077716480, 0.000002082667095075, -0.000136731311264191,
-0.000266155252511831, -0.000383371840261246, -0.000485996080304965, -0.000572115873292030, -0.000640319946685634,
-0.000689709694056092, -0.000719899536922384, -0.000731002305621048, -0.000723604675185869, -0.000698728981427767,
-0.000657788245032425, -0.000602532044011899, -0.000534985542936898, -0.000457387566635848, -0.000372121907291206,
-0.000281651282503015, -0.000188451833293202, -0.000094949813106744, -0.000003462782744354, 0.000083853091464077,
0.000165048886226905, 0.000238422248479072, 0.000302547334727027, 0.000356297600912998, 0.000398857326863837,
0.000429729020814434, 0.000448726371643413, 0.000455966225408344, 0.000451848709179591, 0.000437031818051652,
0.000412403761615261, 0.000379047713684221, 0.000338204791740229, 0.000291234779803098, 0.000239577162514028,
0.000184710477990398, 0.000128114399130489, 0.000071232572821451, 0.000015440388211825, -0.000037986085678081,
-0.000087895370243821, -0.000133280012107173, -0.000173297342436372, -0.000207273956099563, -0.000234717772155001,
-0.000255317038867589, -0.000268937472718753, -0.000275614059005332, -0.000275541485292432, -0.000269058714331757,
-0.000256632149501508, -0.000238836419299503, -0.000216333899003825, -0.000189854272533545, -0.000160170174848483,
-0.000128080670195777, -0.000094384355854646, -0.000059865389594949, -0.000025277165852799, 0.000008680571408025,
0.000041365841965015, 0.000072210925236429, 0.000100726393185629, 0.000126511346757621, 0.000149250512353807,
0.000168719942655099, 0.000184780318878738, 0.000197379393194548, 0.000206539880117977, 0.000212358734245594,
0.000214994859281552, 0.000214655997661182, 0.000211604878787747, 0.000206128795372885, 0.000198541881389953,
0.000189176709991702, 0.000178368313347299, 0.000166450784469067, 0.000153744508371709, 0.000140558396336177,
0.000127174196746337, 0.000113853476544409, 0.000100818605854714, 0.000088271373315159, 0.000076360900545177,
0.000065233162392019, 0.000054970017069384, 0.000045630720487935, 0.000037271082107518, 0.000029885221425020,
0.000023463361155584, 0.000017966192635412, 0.000013350669444763, 0.000009551098482930, 0.000006499942123311,
0.000004115682735322, 0.000002322193058869, 0.000001038946634000, 0.000000197734700398, -0.000000267011791999,
-0.000005050567303837 };
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,70 @@
/*---------------------------------------------------------------------------*\
FILE........: freedv_data_channel.h
AUTHOR......: Jeroen Vreeken
DATE CREATED: 03 March 2016
Data channel for ethernet like packets in freedv VHF frames.
Currently designed for-
* 2 control bits per frame
* 4 byte counter bits per frame
* 64 bits of data per frame
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2016 Jeroen Vreeken
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _FREEDV_DATA_CHANNEL_H
#define _FREEDV_DATA_CHANNEL_H
#include <stdlib.h>
#define FREEDV_DATA_CHANNEL_PACKET_MAX 2048
typedef void (*freedv_data_callback_rx)(void *, unsigned char *packet, size_t size);
typedef void (*freedv_data_callback_tx)(void *, unsigned char *packet, size_t *size);
struct freedv_data_channel {
freedv_data_callback_rx cb_rx;
void *cb_rx_state;
freedv_data_callback_tx cb_tx;
void *cb_tx_state;
unsigned char rx_header[8];
unsigned char packet_rx[FREEDV_DATA_CHANNEL_PACKET_MAX + 2];
int packet_rx_cnt;
unsigned char tx_header[8];
unsigned char packet_tx[FREEDV_DATA_CHANNEL_PACKET_MAX + 2];
int packet_tx_cnt;
size_t packet_tx_size;
};
struct freedv_data_channel *freedv_data_channel_create(void);
void freedv_data_channel_destroy(struct freedv_data_channel *fdc);
void freedv_data_set_cb_rx(struct freedv_data_channel *fdc, freedv_data_callback_rx cb, void *state);
void freedv_data_set_cb_tx(struct freedv_data_channel *fdc, freedv_data_callback_tx cb, void *state);
void freedv_data_channel_rx_frame(struct freedv_data_channel *fdc, unsigned char *data, size_t size, int from_bit, int bcast_bit, int crc_bit, int end_bits);
void freedv_data_channel_tx_frame(struct freedv_data_channel *fdc, unsigned char *data, size_t size, int *from_bit, int *bcast_bit, int *crc_bit, int *end_bits);
void freedv_data_set_header(struct freedv_data_channel *fdc, unsigned char *header);
int freedv_data_get_n_tx_frames(struct freedv_data_channel *fdc, size_t size);
#endif /* _FREEDV_DATA_CHANNEL_H */
+93
View File
@@ -0,0 +1,93 @@
/*---------------------------------------------------------------------------*\
FILE........: freedv_vhf_framing.h
AUTHOR......: Brady O'Brien
DATE CREATED: 11 February 2016
Framer and deframer for VHF FreeDV modes 'A' and 'B'
Currently designed for-
* 40ms ota modem frames
* 40ms Codec2 1300 frames
* 52 bits of Codec2 per frame
* 16 bits of unique word per frame
* 28 'spare' bits per frame
* - 4 spare bits at front and end of frame (8 total) for padding
* - 20 'protocol' bits, either for higher layers of 'protocol' or
* - 18 'protocol' bits and 2 vericode sidechannel bits
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2016 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _FREEDV_VHF_FRAMING_H
#define _FREEDV_VHF_FRAMING_H
#include "freedv_data_channel.h"
/* Standard frame type */
#define FREEDV_VHF_FRAME_A 1 /* 2400A/B Frame */
#define FREEDV_HF_FRAME_B 2 /* 800XA Frame */
#define FREEDV_VHF_FRAME_AT 3 /* 4800T Frame */
struct freedv_vhf_deframer {
int ftype; /* Type of frame to be looking for */
int state; /* State of deframer */
uint8_t * bits; /* Bits currently being decanted */
uint8_t * invbits; /* Inversion of bits currently being decanted, for FMFSK */
int bitptr; /* Pointer into circular bit buffer */
int miss_cnt; /* How many UWs have been missed */
int last_uw; /* How many bits since the last UW? */
int frame_size; /* How big is a frame? */
int uw_size; /* How big is the UW */
int on_inv_bits; /* Are we using the inverted bits? */
int sym_size; /* How many bits in a modem symbol */
float ber_est; /* Bit error rate estimate */
int total_uw_bits; /* Total RX-ed bits of UW */
int total_uw_err; /* Total errors in UW bits */
struct freedv_data_channel *fdc;
};
/* Init and allocate memory for a freedv-vhf framer/deframer */
struct freedv_vhf_deframer * fvhff_create_deframer(uint8_t frame_type,int enable_bit_flip);
/* Get size of various frame parameters */
/* Frame size in bits */
int fvhff_get_frame_size(struct freedv_vhf_deframer * def);
/* Codec2 size in bytes */
int fvhff_get_codec2_size(struct freedv_vhf_deframer * def);
/* Protocol bits in bits */
int fvhff_get_proto_size(struct freedv_vhf_deframer * def);
/* Varicode bits in bits */
int fvhff_get_varicode_size(struct freedv_vhf_deframer * def);
/* Free the memory used by a freedv-vhf framer/deframer */
void fvhff_destroy_deframer(struct freedv_vhf_deframer * def);
/* Place codec and other bits into a frame */
void fvhff_frame_bits(int frame_type,uint8_t bits_out[],uint8_t codec2_in[],uint8_t proto_in[],uint8_t vc_in[]);
void fvhff_frame_data_bits(struct freedv_vhf_deframer * def, int frame_type,uint8_t bits_out[]);
/* Find and extract frames from a stream of bits */
int fvhff_deframe_bits(struct freedv_vhf_deframer * def,uint8_t codec2_out[],uint8_t proto_out[],uint8_t vc_out[],uint8_t bits_in[]);
/* Is the de-framer synchronized? */
int fvhff_synchronized(struct freedv_vhf_deframer * def);
#endif //_FREEDV_VHF_FRAMING_H
+190
View File
@@ -0,0 +1,190 @@
/*---------------------------------------------------------------------------*\
FILE........: fsk.h
AUTHOR......: Brady O'Brien
DATE CREATED: 6 January 2016
C Implementation of 2FSK/4FSK modulator/demodulator, based on octave/fsk_horus.m
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2016 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __C2FSK_H
#define __C2FSK_H
#include <stdint.h>
#include "comp.h"
#include "kiss_fftr.h"
#include "modem_stats.h"
#define MODE_2FSK 2
#define MODE_4FSK 4
#define MODE_M_MAX 4
#define FSK_SCALE 16383
struct FSK {
/* Static parameters set up by fsk_init */
int Ndft; /* buffer size for freq offset est fft */
int Fs; /* sample freq */
int N; /* processing buffer size */
int Rs; /* symbol rate */
int Ts; /* samples per symbol */
int Nmem; /* size of extra mem for timing adj */
int P; /* oversample rate for timing est/adj */
int Nsym; /* Number of symbols spat out in a processing frame */
int Nbits; /* Number of bits spat out in a processing frame */
int f1_tx; /* f1 for modulator */
int fs_tx; /* Space between TX freqs for modulatosr */
int mode; /* 2FSK or 4FSK */
int est_min; /* Minimum frequency for freq. estimator */
int est_max; /* Maximum frequency for freq. estimaotr */
int est_space; /* Minimum frequency spacing for freq. estimator */
float* hann_table; /* Precomputed or runtime computed hann window table */
/* Parameters used by demod */
COMP phi_c[MODE_M_MAX];
kiss_fft_cfg fft_cfg; /* Config for KISS FFT, used in freq est */
float norm_rx_timing; /* Normalized RX timing */
COMP* samp_old; /* Tail end of last batch of samples */
int nstash; /* How many elements are in there */
float* fft_est; /* Freq est FFT magnitude */
/* Memory used by demod but not important between demod frames */
/* Parameters used by mod */
COMP tx_phase_c; /* TX phase, but complex */
/* Statistics generated by demod */
float EbNodB; /* Estimated EbNo in dB */
float f_est[MODE_M_MAX];/* Estimated frequencies */
float ppm; /* Estimated PPM clock offset */
/* Parameters used by mod/demod and driving code */
int nin; /* Number of samples to feed the next demod cycle */
/* modem statistic struct */
struct MODEM_STATS *stats;
int normalise_eye; /* enables/disables normalisation of eye diagram */
};
/*
* Create an FSK config/state struct from a set of config parameters
*
* int Fs - Sample frequency
* int Rs - Symbol rate
* int tx_f1 - '0' frequency
* int tx_fs - frequency spacing
*/
struct FSK * fsk_create(int Fs, int Rs, int M, int tx_f1, int tx_fs);
/*
* Create an FSK config/state struct from a set of config parameters
*
* int Fs - Sample frequency
* int Rs - Symbol rate
* int tx_f1 - '0' frequency
* int tx_fs - frequency spacing
*/
struct FSK * fsk_create_hbr(int Fs, int Rs, int P, int M, int tx_f1, int tx_fs);
/*
* Set a new number of symbols per processing frame
*/
void fsk_set_nsym(struct FSK *fsk,int nsym);
/*
* Set the minimum and maximum frequencies at which the freq. estimator can find tones
*/
void fsk_set_est_limits(struct FSK *fsk,int fmin, int fmax);
/*
* Clear the estimator states
*/
void fsk_clear_estimators(struct FSK *fsk);
/*
* Fills MODEM_STATS struct with demod statistics
*/
void fsk_get_demod_stats(struct FSK *fsk, struct MODEM_STATS *stats);
/*
* Destroy an FSK state struct and free it's memory
*
* struct FSK *fsk - FSK config/state struct to be destroyed
*/
void fsk_destroy(struct FSK *fsk);
/*
* Modulates Nsym bits into N samples
*
* struct FSK *fsk - FSK config/state struct, set up by fsk_create
* float fsk_out[] - Buffer for N samples of modulated FSK
* uint8_t tx_bits[] - Buffer containing Nbits unpacked bits
*/
void fsk_mod(struct FSK *fsk, float fsk_out[], uint8_t tx_bits[]);
/*
* Modulates Nsym bits into N complex samples
*
* struct FSK *fsk - FSK config/state struct, set up by fsk_create
* comp fsk_out[] - Buffer for N samples of modulated FSK
* uint8_t tx_bits[] - Buffer containing Nbits unpacked bits
*/
void fsk_mod_c(struct FSK *fsk, COMP fsk_out[], uint8_t tx_bits[]);
/*
* Returns the number of samples needed for the next fsk_demod() cycle
*
* struct FSK *fsk - FSK config/state struct, set up by fsk_create
* returns - number of samples to be fed into fsk_demod next cycle
*/
uint32_t fsk_nin(struct FSK *fsk);
/*
* Demodulate some number of FSK samples. The number of samples to be
* demodulated can be found by calling fsk_nin().
*
* struct FSK *fsk - FSK config/state struct, set up by fsk_create
* uint8_t rx_bits[] - Buffer for Nbits unpacked bits to be written
* float fsk_in[] - nin samples of modualted FSK
*/
void fsk_demod(struct FSK *fsk, uint8_t rx_bits[],COMP fsk_in[]);
/*
* Demodulate some number of FSK samples. The number of samples to be
* demodulated can be found by calling fsk_nin().
*
* struct FSK *fsk - FSK config/state struct, set up by fsk_create
* float rx_bits[] - Buffer for Nbits soft decision bits to be written
* float fsk_in[] - nin samples of modualted FSK
*/
void fsk_demod_sd(struct FSK *fsk, float rx_bits[],COMP fsk_in[]);
/* enables/disables normalisation of eye diagram samples */
void fsk_stats_normalise_eye(struct FSK *fsk, int normalise_enable);
#endif
+44
View File
@@ -0,0 +1,44 @@
/*---------------------------------------------------------------------------*\
FILE........: golay23.h
AUTHOR......: David Rowe
DATE CREATED: 3 March 2013
Header file for Golay FEC.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2013 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GOLAY23__
#define __GOLAY23__
#ifdef __cplusplus
extern "C" {
#endif
void golay23_init(void);
int golay23_encode(int data);
int golay23_decode(int received_codeword);
int golay23_count_errors(int recd_codeword, int corrected_codeword);
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+644
View File
@@ -0,0 +1,644 @@
/* Generated by hanning_file() Octave function */
const float hanning[]={
0,
2.4171e-05,
9.66816e-05,
0.000217525,
0.000386689,
0.000604158,
0.00086991,
0.00118392,
0.00154616,
0.00195659,
0.00241517,
0.00292186,
0.00347661,
0.00407937,
0.00473008,
0.00542867,
0.00617507,
0.00696922,
0.00781104,
0.00870045,
0.00963736,
0.0106217,
0.0116533,
0.0127322,
0.0138581,
0.0150311,
0.0162509,
0.0175175,
0.0188308,
0.0201906,
0.0215968,
0.0230492,
0.0245478,
0.0260923,
0.0276826,
0.0293186,
0.0310001,
0.032727,
0.034499,
0.036316,
0.0381779,
0.0400844,
0.0420354,
0.0440307,
0.04607,
0.0481533,
0.0502802,
0.0524506,
0.0546643,
0.056921,
0.0592206,
0.0615627,
0.0639473,
0.0663741,
0.0688427,
0.0713531,
0.0739048,
0.0764978,
0.0791318,
0.0818064,
0.0845214,
0.0872767,
0.0900718,
0.0929066,
0.0957807,
0.0986939,
0.101646,
0.104636,
0.107665,
0.110732,
0.113836,
0.116978,
0.120156,
0.123372,
0.126624,
0.129912,
0.133235,
0.136594,
0.139989,
0.143418,
0.146881,
0.150379,
0.153911,
0.157476,
0.161074,
0.164705,
0.168368,
0.172063,
0.17579,
0.179549,
0.183338,
0.187158,
0.191008,
0.194888,
0.198798,
0.202737,
0.206704,
0.2107,
0.214724,
0.218775,
0.222854,
0.226959,
0.231091,
0.235249,
0.239432,
0.243641,
0.247874,
0.252132,
0.256414,
0.260719,
0.265047,
0.269398,
0.273772,
0.278167,
0.282584,
0.287021,
0.29148,
0.295958,
0.300456,
0.304974,
0.30951,
0.314065,
0.318638,
0.323228,
0.327835,
0.332459,
0.3371,
0.341756,
0.346427,
0.351113,
0.355814,
0.360528,
0.365256,
0.369997,
0.374751,
0.379516,
0.384293,
0.389082,
0.393881,
0.398691,
0.40351,
0.408338,
0.413176,
0.418022,
0.422876,
0.427737,
0.432605,
0.43748,
0.44236,
0.447247,
0.452138,
0.457034,
0.461935,
0.466839,
0.471746,
0.476655,
0.481568,
0.486481,
0.491397,
0.496313,
0.501229,
0.506145,
0.511061,
0.515976,
0.520889,
0.5258,
0.530708,
0.535614,
0.540516,
0.545414,
0.550308,
0.555197,
0.560081,
0.564958,
0.56983,
0.574695,
0.579552,
0.584402,
0.589244,
0.594077,
0.598901,
0.603715,
0.60852,
0.613314,
0.618097,
0.622868,
0.627628,
0.632375,
0.63711,
0.641831,
0.646538,
0.651232,
0.655911,
0.660574,
0.665222,
0.669855,
0.67447,
0.679069,
0.683651,
0.688215,
0.69276,
0.697287,
0.701795,
0.706284,
0.710752,
0.7152,
0.719627,
0.724033,
0.728418,
0.73278,
0.73712,
0.741437,
0.74573,
0.75,
0.754246,
0.758467,
0.762663,
0.766833,
0.770978,
0.775097,
0.779189,
0.783254,
0.787291,
0.791301,
0.795283,
0.799236,
0.80316,
0.807055,
0.810921,
0.814756,
0.81856,
0.822334,
0.826077,
0.829788,
0.833468,
0.837115,
0.840729,
0.844311,
0.847859,
0.851374,
0.854855,
0.858301,
0.861713,
0.86509,
0.868431,
0.871737,
0.875007,
0.87824,
0.881437,
0.884598,
0.887721,
0.890806,
0.893854,
0.896864,
0.899835,
0.902768,
0.905661,
0.908516,
0.911331,
0.914106,
0.916841,
0.919536,
0.92219,
0.924804,
0.927376,
0.929907,
0.932397,
0.934845,
0.93725,
0.939614,
0.941935,
0.944213,
0.946448,
0.94864,
0.950789,
0.952894,
0.954955,
0.956972,
0.958946,
0.960874,
0.962759,
0.964598,
0.966393,
0.968142,
0.969846,
0.971505,
0.973118,
0.974686,
0.976207,
0.977683,
0.979112,
0.980495,
0.981832,
0.983122,
0.984365,
0.985561,
0.986711,
0.987813,
0.988868,
0.989876,
0.990837,
0.99175,
0.992616,
0.993434,
0.994204,
0.994927,
0.995601,
0.996228,
0.996807,
0.997337,
0.99782,
0.998255,
0.998641,
0.998979,
0.999269,
0.999511,
0.999704,
0.999849,
0.999946,
0.999994,
0.999994,
0.999946,
0.999849,
0.999704,
0.999511,
0.999269,
0.998979,
0.998641,
0.998255,
0.99782,
0.997337,
0.996807,
0.996228,
0.995601,
0.994927,
0.994204,
0.993434,
0.992616,
0.99175,
0.990837,
0.989876,
0.988868,
0.987813,
0.986711,
0.985561,
0.984365,
0.983122,
0.981832,
0.980495,
0.979112,
0.977683,
0.976207,
0.974686,
0.973118,
0.971505,
0.969846,
0.968142,
0.966393,
0.964598,
0.962759,
0.960874,
0.958946,
0.956972,
0.954955,
0.952894,
0.950789,
0.94864,
0.946448,
0.944213,
0.941935,
0.939614,
0.93725,
0.934845,
0.932397,
0.929907,
0.927376,
0.924804,
0.92219,
0.919536,
0.916841,
0.914106,
0.911331,
0.908516,
0.905661,
0.902768,
0.899835,
0.896864,
0.893854,
0.890806,
0.887721,
0.884598,
0.881437,
0.87824,
0.875007,
0.871737,
0.868431,
0.86509,
0.861713,
0.858301,
0.854855,
0.851374,
0.847859,
0.844311,
0.840729,
0.837115,
0.833468,
0.829788,
0.826077,
0.822334,
0.81856,
0.814756,
0.810921,
0.807055,
0.80316,
0.799236,
0.795283,
0.791301,
0.787291,
0.783254,
0.779189,
0.775097,
0.770978,
0.766833,
0.762663,
0.758467,
0.754246,
0.75,
0.74573,
0.741437,
0.73712,
0.73278,
0.728418,
0.724033,
0.719627,
0.7152,
0.710752,
0.706284,
0.701795,
0.697287,
0.69276,
0.688215,
0.683651,
0.679069,
0.67447,
0.669855,
0.665222,
0.660574,
0.655911,
0.651232,
0.646538,
0.641831,
0.63711,
0.632375,
0.627628,
0.622868,
0.618097,
0.613314,
0.60852,
0.603715,
0.598901,
0.594077,
0.589244,
0.584402,
0.579552,
0.574695,
0.56983,
0.564958,
0.560081,
0.555197,
0.550308,
0.545414,
0.540516,
0.535614,
0.530708,
0.5258,
0.520889,
0.515976,
0.511061,
0.506145,
0.501229,
0.496313,
0.491397,
0.486481,
0.481568,
0.476655,
0.471746,
0.466839,
0.461935,
0.457034,
0.452138,
0.447247,
0.44236,
0.43748,
0.432605,
0.427737,
0.422876,
0.418022,
0.413176,
0.408338,
0.40351,
0.398691,
0.393881,
0.389082,
0.384293,
0.379516,
0.374751,
0.369997,
0.365256,
0.360528,
0.355814,
0.351113,
0.346427,
0.341756,
0.3371,
0.332459,
0.327835,
0.323228,
0.318638,
0.314065,
0.30951,
0.304974,
0.300456,
0.295958,
0.29148,
0.287021,
0.282584,
0.278167,
0.273772,
0.269398,
0.265047,
0.260719,
0.256414,
0.252132,
0.247874,
0.243641,
0.239432,
0.235249,
0.231091,
0.226959,
0.222854,
0.218775,
0.214724,
0.2107,
0.206704,
0.202737,
0.198798,
0.194888,
0.191008,
0.187158,
0.183338,
0.179549,
0.17579,
0.172063,
0.168368,
0.164705,
0.161074,
0.157476,
0.153911,
0.150379,
0.146881,
0.143418,
0.139989,
0.136594,
0.133235,
0.129912,
0.126624,
0.123372,
0.120156,
0.116978,
0.113836,
0.110732,
0.107665,
0.104636,
0.101646,
0.0986939,
0.0957807,
0.0929066,
0.0900718,
0.0872767,
0.0845214,
0.0818064,
0.0791318,
0.0764978,
0.0739048,
0.0713531,
0.0688427,
0.0663741,
0.0639473,
0.0615627,
0.0592206,
0.056921,
0.0546643,
0.0524506,
0.0502802,
0.0481533,
0.04607,
0.0440307,
0.0420354,
0.0400844,
0.0381779,
0.036316,
0.034499,
0.032727,
0.0310001,
0.0293186,
0.0276826,
0.0260923,
0.0245478,
0.0230492,
0.0215968,
0.0201906,
0.0188308,
0.0175175,
0.0162509,
0.0150311,
0.0138581,
0.0127322,
0.0116533,
0.0106217,
0.00963736,
0.00870045,
0.00781104,
0.00696922,
0.00617507,
0.00542867,
0.00473008,
0.00407937,
0.00347661,
0.00292186,
0.00241517,
0.00195659,
0.00154616,
0.00118392,
0.00086991,
0.000604158,
0.000386689,
0.000217525,
9.66816e-05,
2.4171e-05,
0
};
+23
View File
@@ -0,0 +1,23 @@
/*---------------------------------------------------------------------------*\
FILE........: horus_l2.h
AUTHOR......: David Rowe
DATE CREATED: Dec 2015
\*---------------------------------------------------------------------------*/
#ifndef __HORUS_L2__
#define __HORUS_L2__
int horus_l2_get_num_tx_data_bytes(int num_payload_data_bytes);
/* returns number of output bytes in output_tx_data */
int horus_l2_encode_tx_packet(unsigned char *output_tx_data,
unsigned char *input_payload_data,
int num_payload_data_bytes);
void horus_l2_decode_rx_packet(unsigned char *output_payload_data,
unsigned char *input_rx_data,
int num_payload_data_bytes);
#endif
+107
View File
@@ -0,0 +1,107 @@
/* Hilbert Transform FIR filter coeffs */
/* Generated by make_hilb Octave script */
#define HT_N 100
COMP ht_coeff[]={
{0.000000,0.000000},
{-0.000000,-0.000001},
{0.000000,0.000000},
{-0.000000,-0.000017},
{0.000000,0.000000},
{0.000000,-0.000079},
{0.000000,0.000000},
{0.000000,-0.000217},
{0.000000,0.000000},
{0.000000,-0.000461},
{0.000000,0.000000},
{-0.000000,-0.000842},
{0.000000,0.000000},
{-0.000000,-0.001391},
{0.000000,0.000000},
{-0.000000,-0.002140},
{0.000000,0.000000},
{-0.000000,-0.003121},
{0.000000,0.000000},
{0.000000,-0.004371},
{0.000000,0.000000},
{0.000000,-0.005928},
{0.000000,0.000000},
{-0.000000,-0.007839},
{0.000000,0.000000},
{-0.000000,-0.010159},
{0.000000,0.000000},
{-0.000000,-0.012957},
{0.000000,0.000000},
{-0.000000,-0.016327},
{0.000000,0.000000},
{0.000000,-0.020399},
{0.000000,0.000000},
{-0.000000,-0.025364},
{0.000000,0.000000},
{0.000000,-0.031512},
{0.000000,0.000000},
{0.000000,-0.039319},
{0.000000,0.000000},
{0.000000,-0.049610},
{0.000000,0.000000},
{-0.000000,-0.063952},
{0.000000,0.000000},
{-0.000000,-0.085722},
{0.000000,0.000000},
{0.000000,-0.123718},
{0.000000,0.000000},
{0.000000,-0.210249},
{0.000000,0.000000},
{-0.000000,-0.636250},
{0.999748,0.000000},
{0.000000,0.634969},
{0.000000,0.000000},
{0.000000,0.208979},
{0.000000,0.000000},
{0.000000,0.122467},
{0.000000,0.000000},
{-0.000000,0.084502},
{0.000000,0.000000},
{0.000000,0.062771},
{0.000000,0.000000},
{0.000000,0.048477},
{0.000000,0.000000},
{0.000000,0.038242},
{0.000000,0.000000},
{-0.000000,0.030497},
{0.000000,0.000000},
{0.000000,0.024418},
{0.000000,0.000000},
{0.000000,0.019527},
{0.000000,0.000000},
{-0.000000,0.015532},
{0.000000,0.000000},
{0.000000,0.012242},
{0.000000,0.000000},
{-0.000000,0.009524},
{0.000000,0.000000},
{-0.000000,0.007285},
{0.000000,0.000000},
{-0.000000,0.005454},
{0.000000,0.000000},
{-0.000000,0.003973},
{0.000000,0.000000},
{0.000000,0.002796},
{0.000000,0.000000},
{-0.000000,0.001882},
{0.000000,0.000000},
{-0.000000,0.001196},
{0.000000,0.000000},
{-0.000000,0.000701},
{0.000000,0.000000},
{0.000000,0.000367},
{0.000000,0.000000},
{0.000000,0.000160},
{0.000000,0.000000},
{0.000000,0.000051},
{0.000000,0.000000},
{-0.000000,0.000008},
{0.000000,0.000000},
{0.000000,0.000000}
};
+331
View File
@@ -0,0 +1,331 @@
/*---------------------------------------------------------------------------*\
FILE........: interp.c
AUTHOR......: David Rowe
DATE CREATED: 9/10/09
Interpolation of 20ms frames to 10ms frames.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include "defines.h"
#include "interp.h"
#include "lsp.h"
#include "quantise.h"
float sample_log_amp(MODEL *model, float w);
#if 0
/*---------------------------------------------------------------------------*\
FUNCTION....: interp()
AUTHOR......: David Rowe
DATE CREATED: 22/8/10
Given two frames decribed by model parameters 20ms apart, determines
the model parameters of the 10ms frame between them. Assumes
voicing is available for middle (interpolated) frame. Outputs are
amplitudes and Wo for the interpolated frame.
This version can interpolate the amplitudes between two frames of
different Wo and L.
This version works by log linear interpolation, but listening tests
showed it creates problems in background noise, e.g. hts2a and mmt1.
When this function is used (--dec mode) bg noise appears to be
amplitude modulated, and gets louder. The interp_lsp() function
below seems to do a better job.
\*---------------------------------------------------------------------------*/
void interpolate(
MODEL *interp, /* interpolated model params */
MODEL *prev, /* previous frames model params */
MODEL *next, /* next frames model params */
float Wo_min
)
{
int l;
float w,log_amp;
/* Wo depends on voicing of this and adjacent frames */
if (interp->voiced) {
if (prev->voiced && next->voiced)
interp->Wo = (prev->Wo + next->Wo)/2.0;
if (!prev->voiced && next->voiced)
interp->Wo = next->Wo;
if (prev->voiced && !next->voiced)
interp->Wo = prev->Wo;
}
else {
interp->Wo = Wo_min;
}
interp->L = PI/interp->Wo;
/* Interpolate amplitudes using linear interpolation in log domain */
for(l=1; l<=interp->L; l++) {
w = l*interp->Wo;
log_amp = (sample_log_amp(prev, w) + sample_log_amp(next, w))/2.0;
interp->A[l] = powf(10.0, log_amp);
}
}
#endif
/*---------------------------------------------------------------------------*\
FUNCTION....: sample_log_amp()
AUTHOR......: David Rowe
DATE CREATED: 22/8/10
Samples the amplitude envelope at an arbitrary frequency w. Uses
linear interpolation in the log domain to sample between harmonic
amplitudes.
\*---------------------------------------------------------------------------*/
float sample_log_amp(MODEL *model, float w)
{
int m;
float f, log_amp;
assert(w > 0.0); assert (w <= PI);
m = floorf(w/model->Wo + 0.5);
f = (w - m*model->Wo)/w;
assert(f <= 1.0);
if (m < 1) {
log_amp = f*log10f(model->A[1] + 1E-6);
}
else if ((m+1) > model->L) {
log_amp = (1.0-f)*log10f(model->A[model->L] + 1E-6);
}
else {
log_amp = (1.0-f)*log10f(model->A[m] + 1E-6) +
f*log10f(model->A[m+1] + 1E-6);
}
return log_amp;
}
#ifdef NOT_NEEDED
/*---------------------------------------------------------------------------*\
FUNCTION....: interp_lsp()
AUTHOR......: David Rowe
DATE CREATED: 10 Nov 2010
Given two frames decribed by model parameters 20ms apart, determines
the model parameters of the 10ms frame between them. Assumes
voicing is available for middle (interpolated) frame. Outputs are
amplitudes and Wo for the interpolated frame.
This version uses interpolation of LSPs, seems to do a better job
with bg noise.
\*---------------------------------------------------------------------------*/
void interpolate_lsp(
codec2_fft_cfg fft_fwd_cfg,
MODEL *interp, /* interpolated model params */
MODEL *prev, /* previous frames model params */
MODEL *next, /* next frames model params */
float *prev_lsps, /* previous frames LSPs */
float prev_e, /* previous frames LPC energy */
float *next_lsps, /* next frames LSPs */
float next_e, /* next frames LPC energy */
float *ak_interp, /* interpolated aks for this frame */
float *lsps_interp, /* interpolated lsps for this frame */
float Wo_min
)
{
int i;
float e;
float snr;
/* trap corner case where V est is probably wrong */
if (interp->voiced && !prev->voiced && !next->voiced) {
interp->voiced = 0;
}
/* Wo depends on voicing of this and adjacent frames */
if (interp->voiced) {
if (prev->voiced && next->voiced)
interp->Wo = (prev->Wo + next->Wo)/2.0;
if (!prev->voiced && next->voiced)
interp->Wo = next->Wo;
if (prev->voiced && !next->voiced)
interp->Wo = prev->Wo;
}
else {
interp->Wo = Wo_min;
}
interp->L = PI/interp->Wo;
//printf(" interp: prev_v: %d next_v: %d prev_Wo: %f next_Wo: %f\n",
// prev->voiced, next->voiced, prev->Wo, next->Wo);
//printf(" interp: Wo: %1.5f L: %d\n", interp->Wo, interp->L);
/* interpolate LSPs */
for(i=0; i<LPC_ORD; i++) {
lsps_interp[i] = (prev_lsps[i] + next_lsps[i])/2.0;
}
/* Interpolate LPC energy in log domain */
e = powf(10.0, (log10f(prev_e) + log10f(next_e))/2.0);
//printf(" interp: e: %f\n", e);
/* convert back to amplitudes */
lsp_to_lpc(lsps_interp, ak_interp, LPC_ORD);
aks_to_M2(fft_fwd_cfg, ak_interp, LPC_ORD, interp, e, &snr, 0, 0, 1, 1, LPCPF_BETA, LPCPF_GAMMA);
//printf(" interp: ak[1]: %f A[1] %f\n", ak_interp[1], interp->A[1]);
}
#endif
/*---------------------------------------------------------------------------*\
FUNCTION....: interp_Wo()
AUTHOR......: David Rowe
DATE CREATED: 22 May 2012
Interpolates centre 10ms sample of Wo and L samples given two
samples 20ms apart. Assumes voicing is available for centre
(interpolated) frame.
\*---------------------------------------------------------------------------*/
void interp_Wo(
MODEL *interp, /* interpolated model params */
MODEL *prev, /* previous frames model params */
MODEL *next, /* next frames model params */
float Wo_min
)
{
interp_Wo2(interp, prev, next, 0.5, Wo_min);
}
/*---------------------------------------------------------------------------*\
FUNCTION....: interp_Wo2()
AUTHOR......: David Rowe
DATE CREATED: 22 May 2012
Weighted interpolation of two Wo samples.
\*---------------------------------------------------------------------------*/
void interp_Wo2(
MODEL *interp, /* interpolated model params */
MODEL *prev, /* previous frames model params */
MODEL *next, /* next frames model params */
float weight,
float Wo_min
)
{
/* trap corner case where voicing est is probably wrong */
if (interp->voiced && !prev->voiced && !next->voiced) {
interp->voiced = 0;
}
/* Wo depends on voicing of this and adjacent frames */
if (interp->voiced) {
if (prev->voiced && next->voiced)
interp->Wo = (1.0 - weight)*prev->Wo + weight*next->Wo;
if (!prev->voiced && next->voiced)
interp->Wo = next->Wo;
if (prev->voiced && !next->voiced)
interp->Wo = prev->Wo;
}
else {
interp->Wo = Wo_min;
}
interp->L = PI/interp->Wo;
}
/*---------------------------------------------------------------------------*\
FUNCTION....: interp_energy()
AUTHOR......: David Rowe
DATE CREATED: 22 May 2012
Interpolates centre 10ms sample of energy given two samples 20ms
apart.
\*---------------------------------------------------------------------------*/
float interp_energy(float prev_e, float next_e)
{
//return powf(10.0, (log10f(prev_e) + log10f(next_e))/2.0);
return sqrtf(prev_e * next_e); //looks better is math. identical and faster math
}
/*---------------------------------------------------------------------------*\
FUNCTION....: interp_energy2()
AUTHOR......: David Rowe
DATE CREATED: 22 May 2012
Interpolates centre 10ms sample of energy given two samples 20ms
apart.
\*---------------------------------------------------------------------------*/
float interp_energy2(float prev_e, float next_e, float weight)
{
return powf(10.0, (1.0 - weight)*log10f(prev_e) + weight*log10f(next_e));
}
/*---------------------------------------------------------------------------*\
FUNCTION....: interpolate_lsp_ver2()
AUTHOR......: David Rowe
DATE CREATED: 22 May 2012
Weighted interpolation of LSPs.
\*---------------------------------------------------------------------------*/
void interpolate_lsp_ver2(float interp[], float prev[], float next[], float weight, int order)
{
int i;
for(i=0; i<order; i++)
interp[i] = (1.0 - weight)*prev[i] + weight*next[i];
}
+45
View File
@@ -0,0 +1,45 @@
/*---------------------------------------------------------------------------*\
FILE........: interp.h
AUTHOR......: David Rowe
DATE CREATED: 9/10/09
Interpolation of 20ms frames to 10ms frames.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __INTERP__
#define __INTERP__
#include "kiss_fft.h"
void interpolate(MODEL *interp, MODEL *prev, MODEL *next);
void interpolate_lsp(kiss_fft_cfg fft_dec_cfg,
MODEL *interp, MODEL *prev, MODEL *next,
float *prev_lsps, float prev_e,
float *next_lsps, float next_e,
float *ak_interp, float *lsps_interp, float Wo_min);
void interp_Wo(MODEL *interp, MODEL *prev, MODEL *next, float Wo_min);
void interp_Wo2(MODEL *interp, MODEL *prev, MODEL *next, float weight, float Wo_min);
float interp_energy(float prev, float next);
float interp_energy2(float prev, float next, float weight);
void interpolate_lsp_ver2(float interp[], float prev[], float next[], float weight, int order);
#endif
+408
View File
@@ -0,0 +1,408 @@
/*
Copyright (c) 2003-2010, Mark Borgerding
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "_kiss_fft_guts.h"
/* The guts header contains all the multiplication and addition macros that are defined for
fixed or floating point complex numbers. It also delares the kf_ internal functions.
*/
static void kf_bfly2(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
int m
)
{
kiss_fft_cpx * Fout2;
kiss_fft_cpx * tw1 = st->twiddles;
kiss_fft_cpx t;
Fout2 = Fout + m;
do{
C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2);
C_MUL (t, *Fout2 , *tw1);
tw1 += fstride;
C_SUB( *Fout2 , *Fout , t );
C_ADDTO( *Fout , t );
++Fout2;
++Fout;
}while (--m);
}
static void kf_bfly4(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
const size_t m
)
{
kiss_fft_cpx *tw1,*tw2,*tw3;
kiss_fft_cpx scratch[6];
size_t k=m;
const size_t m2=2*m;
const size_t m3=3*m;
tw3 = tw2 = tw1 = st->twiddles;
do {
C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4);
C_MUL(scratch[0],Fout[m] , *tw1 );
C_MUL(scratch[1],Fout[m2] , *tw2 );
C_MUL(scratch[2],Fout[m3] , *tw3 );
C_SUB( scratch[5] , *Fout, scratch[1] );
C_ADDTO(*Fout, scratch[1]);
C_ADD( scratch[3] , scratch[0] , scratch[2] );
C_SUB( scratch[4] , scratch[0] , scratch[2] );
C_SUB( Fout[m2], *Fout, scratch[3] );
tw1 += fstride;
tw2 += fstride*2;
tw3 += fstride*3;
C_ADDTO( *Fout , scratch[3] );
if(st->inverse) {
Fout[m].r = scratch[5].r - scratch[4].i;
Fout[m].i = scratch[5].i + scratch[4].r;
Fout[m3].r = scratch[5].r + scratch[4].i;
Fout[m3].i = scratch[5].i - scratch[4].r;
}else{
Fout[m].r = scratch[5].r + scratch[4].i;
Fout[m].i = scratch[5].i - scratch[4].r;
Fout[m3].r = scratch[5].r - scratch[4].i;
Fout[m3].i = scratch[5].i + scratch[4].r;
}
++Fout;
}while(--k);
}
static void kf_bfly3(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
size_t m
)
{
size_t k=m;
const size_t m2 = 2*m;
kiss_fft_cpx *tw1,*tw2;
kiss_fft_cpx scratch[5];
kiss_fft_cpx epi3;
epi3 = st->twiddles[fstride*m];
tw1=tw2=st->twiddles;
do{
C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);
C_MUL(scratch[1],Fout[m] , *tw1);
C_MUL(scratch[2],Fout[m2] , *tw2);
C_ADD(scratch[3],scratch[1],scratch[2]);
C_SUB(scratch[0],scratch[1],scratch[2]);
tw1 += fstride;
tw2 += fstride*2;
Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
C_MULBYSCALAR( scratch[0] , epi3.i );
C_ADDTO(*Fout,scratch[3]);
Fout[m2].r = Fout[m].r + scratch[0].i;
Fout[m2].i = Fout[m].i - scratch[0].r;
Fout[m].r -= scratch[0].i;
Fout[m].i += scratch[0].r;
++Fout;
}while(--k);
}
static void kf_bfly5(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
int m
)
{
kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
int u;
kiss_fft_cpx scratch[13];
kiss_fft_cpx * twiddles = st->twiddles;
kiss_fft_cpx *tw;
kiss_fft_cpx ya,yb;
ya = twiddles[fstride*m];
yb = twiddles[fstride*2*m];
Fout0=Fout;
Fout1=Fout0+m;
Fout2=Fout0+2*m;
Fout3=Fout0+3*m;
Fout4=Fout0+4*m;
tw=st->twiddles;
for ( u=0; u<m; ++u ) {
C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
scratch[0] = *Fout0;
C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
C_ADD( scratch[7],scratch[1],scratch[4]);
C_SUB( scratch[10],scratch[1],scratch[4]);
C_ADD( scratch[8],scratch[2],scratch[3]);
C_SUB( scratch[9],scratch[2],scratch[3]);
Fout0->r += scratch[7].r + scratch[8].r;
Fout0->i += scratch[7].i + scratch[8].i;
scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
C_SUB(*Fout1,scratch[5],scratch[6]);
C_ADD(*Fout4,scratch[5],scratch[6]);
scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
C_ADD(*Fout2,scratch[11],scratch[12]);
C_SUB(*Fout3,scratch[11],scratch[12]);
++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
}
}
/* perform the butterfly for one stage of a mixed radix FFT */
static void kf_bfly_generic(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
int m,
int p
)
{
int u,k,q1,q;
kiss_fft_cpx * twiddles = st->twiddles;
kiss_fft_cpx t;
int Norig = st->nfft;
kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p);
for ( u=0; u<m; ++u ) {
k=u;
for ( q1=0 ; q1<p ; ++q1 ) {
scratch[q1] = Fout[ k ];
C_FIXDIV(scratch[q1],p);
k += m;
}
k=u;
for ( q1=0 ; q1<p ; ++q1 ) {
int twidx=0;
Fout[ k ] = scratch[0];
for (q=1;q<p;++q ) {
twidx += fstride * k;
if (twidx>=Norig) twidx-=Norig;
C_MUL(t,scratch[q] , twiddles[twidx] );
C_ADDTO( Fout[ k ] ,t);
}
k += m;
}
}
KISS_FFT_TMP_FREE(scratch);
}
static
void kf_work(
kiss_fft_cpx * Fout,
const kiss_fft_cpx * f,
const size_t fstride,
int in_stride,
int * factors,
const kiss_fft_cfg st
)
{
kiss_fft_cpx * Fout_beg=Fout;
const int p=*factors++; /* the radix */
const int m=*factors++; /* stage's fft length/p */
const kiss_fft_cpx * Fout_end = Fout + p*m;
#ifdef _OPENMP
// use openmp extensions at the
// top-level (not recursive)
if (fstride==1 && p<=5)
{
int k;
// execute the p different work units in different threads
# pragma omp parallel for
for (k=0;k<p;++k)
kf_work( Fout +k*m, f+ fstride*in_stride*k,fstride*p,in_stride,factors,st);
// all threads have joined by this point
switch (p) {
case 2: kf_bfly2(Fout,fstride,st,m); break;
case 3: kf_bfly3(Fout,fstride,st,m); break;
case 4: kf_bfly4(Fout,fstride,st,m); break;
case 5: kf_bfly5(Fout,fstride,st,m); break;
default: kf_bfly_generic(Fout,fstride,st,m,p); break;
}
return;
}
#endif
if (m==1) {
do{
*Fout = *f;
f += fstride*in_stride;
}while(++Fout != Fout_end );
}else{
do{
// recursive call:
// DFT of size m*p performed by doing
// p instances of smaller DFTs of size m,
// each one takes a decimated version of the input
kf_work( Fout , f, fstride*p, in_stride, factors,st);
f += fstride*in_stride;
}while( (Fout += m) != Fout_end );
}
Fout=Fout_beg;
// recombine the p smaller DFTs
switch (p) {
case 2: kf_bfly2(Fout,fstride,st,m); break;
case 3: kf_bfly3(Fout,fstride,st,m); break;
case 4: kf_bfly4(Fout,fstride,st,m); break;
case 5: kf_bfly5(Fout,fstride,st,m); break;
default: kf_bfly_generic(Fout,fstride,st,m,p); break;
}
}
/* facbuf is populated by p1,m1,p2,m2, ...
where
p[i] * m[i] = m[i-1]
m0 = n */
static
void kf_factor(int n,int * facbuf)
{
int p=4;
double floor_sqrt;
floor_sqrt = floorf( sqrtf((double)n) );
/*factor out powers of 4, powers of 2, then any remaining primes */
do {
while (n % p) {
switch (p) {
case 4: p = 2; break;
case 2: p = 3; break;
default: p += 2; break;
}
if (p > floor_sqrt)
p = n; /* no more factors, skip to end */
}
n /= p;
*facbuf++ = p;
*facbuf++ = n;
} while (n > 1);
}
/*
*
* User-callable function to allocate all necessary storage space for the fft.
*
* The return value is a contiguous block of memory, allocated with malloc. As such,
* It can be freed with free(), rather than a kiss_fft-specific function.
* */
kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem )
{
kiss_fft_cfg st=NULL;
size_t memneeded = sizeof(struct kiss_fft_state)
+ sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/
if ( lenmem==NULL ) {
st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded );
}else{
if (mem != NULL && *lenmem >= memneeded)
st = (kiss_fft_cfg)mem;
*lenmem = memneeded;
}
if (st) {
int i;
st->nfft=nfft;
st->inverse = inverse_fft;
for (i=0;i<nfft;++i) {
const double pi=3.141592653589793238462643383279502884197169399375105820974944;
double phase = -2*pi*i / nfft;
if (st->inverse)
phase *= -1;
kf_cexp(st->twiddles+i, phase );
}
kf_factor(nfft,st->factors);
}
return st;
}
void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
{
if (fin == fout) {
//NOTE: this is not really an in-place FFT algorithm.
//It just performs an out-of-place FFT into a temp buffer
kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft);
kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);
KISS_FFT_TMP_FREE(tmpbuf);
}else{
kf_work( fout, fin, 1,in_stride, st->factors,st );
}
}
void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
{
kiss_fft_stride(cfg,fin,fout,1);
}
void kiss_fft_cleanup(void)
{
// nothing needed any more
}
int kiss_fft_next_fast_size(int n)
{
while(1) {
int m=n;
while ( (m%2) == 0 ) m/=2;
while ( (m%3) == 0 ) m/=3;
while ( (m%5) == 0 ) m/=5;
if (m<=1)
break; /* n is completely factorable by twos, threes, and fives */
n++;
}
return n;
}
+124
View File
@@ -0,0 +1,124 @@
#ifndef KISS_FFT_H
#define KISS_FFT_H
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
ATTENTION!
If you would like a :
-- a utility that will handle the caching of fft objects
-- real-only (no imaginary time component ) FFT
-- a multi-dimensional FFT
-- a command-line utility to perform ffts
-- a command-line utility to perform fast-convolution filtering
Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c
in the tools/ directory.
*/
#ifdef USE_SIMD
# include <xmmintrin.h>
# define kiss_fft_scalar __m128
#define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16)
#define KISS_FFT_FREE _mm_free
#else
#define KISS_FFT_MALLOC malloc
#define KISS_FFT_FREE free
#endif
#ifdef FIXED_POINT
#include <sys/types.h>
# if (FIXED_POINT == 32)
# define kiss_fft_scalar int32_t
# else
# define kiss_fft_scalar int16_t
# endif
#else
# ifndef kiss_fft_scalar
/* default is float */
# define kiss_fft_scalar float
# endif
#endif
typedef struct {
kiss_fft_scalar r;
kiss_fft_scalar i;
}kiss_fft_cpx;
typedef struct kiss_fft_state* kiss_fft_cfg;
/*
* kiss_fft_alloc
*
* Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
*
* typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL);
*
* The return value from fft_alloc is a cfg buffer used internally
* by the fft routine or NULL.
*
* If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc.
* The returned value should be free()d when done to avoid memory leaks.
*
* The state can be placed in a user supplied buffer 'mem':
* If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
* then the function places the cfg in mem and the size used in *lenmem
* and returns mem.
*
* If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
* then the function returns NULL and places the minimum cfg
* buffer size in *lenmem.
* */
kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem);
/*
* kiss_fft(cfg,in_out_buf)
*
* Perform an FFT on a complex input buffer.
* for a forward FFT,
* fin should be f[0] , f[1] , ... ,f[nfft-1]
* fout will be F[0] , F[1] , ... ,F[nfft-1]
* Note that each element is complex and can be accessed like
f[k].r and f[k].i
* */
void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
/*
A more generic version of the above function. It reads its input from every Nth sample.
* */
void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);
/* If kiss_fft_alloc allocated a buffer, it is one contiguous
buffer and can be simply free()d when no longer needed*/
#define kiss_fft_free free
/*
Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up
your compiler output to call this before you exit.
*/
void kiss_fft_cleanup(void);
/*
* Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5)
*/
int kiss_fft_next_fast_size(int n);
/* for real ffts, we need an even size */
#define kiss_fftr_next_fast_size_real(n) \
(kiss_fft_next_fast_size( ((n)+1)>>1)<<1)
#ifdef __cplusplus
}
#endif
#endif
+154
View File
@@ -0,0 +1,154 @@
/*
Copyright (c) 2003-2004, Mark Borgerding
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "kiss_fftr.h"
#include "_kiss_fft_guts.h"
#include "assert.h"
struct kiss_fftr_state{
kiss_fft_cfg substate;
kiss_fft_cpx * tmpbuf;
kiss_fft_cpx * super_twiddles;
#ifdef USE_SIMD
void * pad;
#endif
};
kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
{
int i;
kiss_fftr_cfg st = NULL;
size_t subsize, memneeded;
if (nfft & 1) {
fprintf(stderr,"Real FFT optimization must be even.\n");
return NULL;
}
nfft >>= 1;
kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize);
memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2);
if (lenmem == NULL) {
st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
} else {
if (*lenmem >= memneeded)
st = (kiss_fftr_cfg) mem;
*lenmem = memneeded;
}
if (!st)
return NULL;
st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */
st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize);
st->super_twiddles = st->tmpbuf + nfft;
kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
for (i = 0; i < nfft/2; ++i) {
double phase =
-3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5);
if (inverse_fft)
phase *= -1;
kf_cexp (st->super_twiddles+i,phase);
}
return st;
}
void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
{
/* input buffer timedata is stored row-wise */
int k,ncfft;
kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
assert(st->substate->inverse==0);
ncfft = st->substate->nfft;
/*perform the parallel fft of two real signals packed in real,imag*/
kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
/* The real part of the DC element of the frequency spectrum in st->tmpbuf
* contains the sum of the even-numbered elements of the input time sequence
* The imag part is the sum of the odd-numbered elements
*
* The sum of tdc.r and tdc.i is the sum of the input time sequence.
* yielding DC of input time sequence
* The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
* yielding Nyquist bin of input time sequence
*/
tdc.r = st->tmpbuf[0].r;
tdc.i = st->tmpbuf[0].i;
C_FIXDIV(tdc,2);
CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
freqdata[0].r = tdc.r + tdc.i;
freqdata[ncfft].r = tdc.r - tdc.i;
#ifdef USE_SIMD
freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0);
#else
freqdata[ncfft].i = freqdata[0].i = 0;
#endif
for ( k=1;k <= ncfft/2 ; ++k ) {
fpk = st->tmpbuf[k];
fpnk.r = st->tmpbuf[ncfft-k].r;
fpnk.i = - st->tmpbuf[ncfft-k].i;
C_FIXDIV(fpk,2);
C_FIXDIV(fpnk,2);
C_ADD( f1k, fpk , fpnk );
C_SUB( f2k, fpk , fpnk );
C_MUL( tw , f2k , st->super_twiddles[k-1]);
freqdata[k].r = HALF_OF(f1k.r + tw.r);
freqdata[k].i = HALF_OF(f1k.i + tw.i);
freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r);
freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i);
}
}
void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata)
{
/* input buffer timedata is stored row-wise */
int k, ncfft;
assert(st->substate->inverse == 1);
ncfft = st->substate->nfft;
st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r;
st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r;
C_FIXDIV(st->tmpbuf[0],2);
for (k = 1; k <= ncfft / 2; ++k) {
kiss_fft_cpx fk, fnkc, fek, fok, tmp;
fk = freqdata[k];
fnkc.r = freqdata[ncfft - k].r;
fnkc.i = -freqdata[ncfft - k].i;
C_FIXDIV( fk , 2 );
C_FIXDIV( fnkc , 2 );
C_ADD (fek, fk, fnkc);
C_SUB (tmp, fk, fnkc);
C_MUL (fok, tmp, st->super_twiddles[k-1]);
C_ADD (st->tmpbuf[k], fek, fok);
C_SUB (st->tmpbuf[ncfft - k], fek, fok);
#ifdef USE_SIMD
st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
#else
st->tmpbuf[ncfft - k].i *= -1;
#endif
}
kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
}
+46
View File
@@ -0,0 +1,46 @@
#ifndef KISS_FTR_H
#define KISS_FTR_H
#include "kiss_fft.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
Real optimized version can save about 45% cpu time vs. complex fft of a real seq.
*/
typedef struct kiss_fftr_state *kiss_fftr_cfg;
kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem);
/*
nfft must be even
If you don't care to allocate space, use mem = lenmem = NULL
*/
void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata);
/*
input timedata has nfft scalar points
output freqdata has nfft/2+1 complex points
*/
void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata);
/*
input freqdata has nfft/2+1 complex points
output timedata has nfft scalar points
*/
#define kiss_fftr_free free
#ifdef __cplusplus
}
#endif
#endif
+106
View File
@@ -0,0 +1,106 @@
/*---------------------------------------------------------------------------*\
FILE........: linreg.c
AUTHOR......: David Rowe
DATE CREATED: April 2015
Linear regression C module based on:
http://stackoverflow.com/questions/5083465/fast-efficient-least-squares-fit-algorithm-in-c
Use:
$ gcc linreg.c -o linreg -D__UNITTEST__ -Wall
$ ./linreg
Then compare yfit results with octave/tlinreg.m
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2015 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "linreg.h"
#include "comp_prim.h"
void linreg(COMP *m, COMP *b, float x[], COMP y[], int n)
{
float sumx = 0.0; /* sum of x */
float sumx2 = 0.0; /* sum of x^2 */
COMP sumxy = {0.0,0.0}; /* sum of x * y */
COMP sumy = {0.0,0.0}; /* sum of y */
COMP sumy2 = {0.0,0.0}; /* sum of y**2 */
float denom;
COMP zero;
int i;
for (i=0; i<n; i++) {
sumx += x[i];
sumx2 += x[i]*x[i];
sumxy = cadd(sumxy, fcmult(x[i], y[i]));
sumy = cadd(sumy, y[i]);
sumy2 = cadd(sumy2, cmult(y[i],y[i]));
}
denom = (n * sumx2 - sumx*sumx);
if (denom == 0) {
/* singular matrix. can't solve the problem */
zero.real = 0.0; zero.imag = 0.0;
*m = zero;
*b = zero;
} else {
*m = fcmult(1.0/denom, cadd(fcmult(n, sumxy), cneg(fcmult(sumx,sumy))));
*b = fcmult(1.0/denom, cadd(fcmult(sumx2,sumy), cneg(fcmult(sumx, sumxy))));
}
}
#ifdef __UNITTEST__
static float x[] = {1, 2, 7, 8};
static COMP y[] = {
{-0.70702, 0.70708},
{-0.77314, 0.63442},
{-0.98083, 0.19511},
{-0.99508, 0.09799}
};
int main(void) {
float x1;
COMP m,b,yfit;
linreg(&m, &b, x, y, sizeof(x)/sizeof(float));
for (x1=1; x1<=8; x1++) {
yfit = cadd(fcmult(x1, m),b);
printf("%f %f\n", yfit.real, yfit.imag);
}
return 0;
}
#endif
+35
View File
@@ -0,0 +1,35 @@
/*---------------------------------------------------------------------------*\
FILE........: linreg.h
AUTHOR......: David Rowe
DATE CREATED: April 2015
Linear regression C module based
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2015 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LINREG__
#define __LINREG__
#include "comp.h"
void linreg(COMP *m, COMP *b, float x[], COMP y[], int n);
#endif
+306
View File
@@ -0,0 +1,306 @@
/*---------------------------------------------------------------------------*\
FILE........: lpc.c
AUTHOR......: David Rowe
DATE CREATED: 30 Sep 1990 (!)
Linear Prediction functions written in C.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009-2012 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#define LPC_MAX_N 512 /* maximum no. of samples in frame */
#define PI 3.141592654 /* mathematical constant */
#define ALPHA 1.0
#define BETA 0.94
#include <assert.h>
#include <math.h>
#include "defines.h"
#include "lpc.h"
/*---------------------------------------------------------------------------*\
pre_emp()
Pre-emphasise (high pass filter with zero close to 0 Hz) a frame of
speech samples. Helps reduce dynamic range of LPC spectrum, giving
greater weight and hense a better match to low energy formants.
Should be balanced by de-emphasis of the output speech.
\*---------------------------------------------------------------------------*/
void pre_emp(
float Sn_pre[], /* output frame of speech samples */
float Sn[], /* input frame of speech samples */
float *mem, /* Sn[-1]single sample memory */
int Nsam /* number of speech samples to use */
)
{
int i;
for(i=0; i<Nsam; i++) {
Sn_pre[i] = Sn[i] - ALPHA * mem[0];
mem[0] = Sn[i];
}
}
/*---------------------------------------------------------------------------*\
de_emp()
De-emphasis filter (low pass filter with a pole close to 0 Hz).
\*---------------------------------------------------------------------------*/
void de_emp(
float Sn_de[], /* output frame of speech samples */
float Sn[], /* input frame of speech samples */
float *mem, /* Sn[-1]single sample memory */
int Nsam /* number of speech samples to use */
)
{
int i;
for(i=0; i<Nsam; i++) {
Sn_de[i] = Sn[i] + BETA * mem[0];
mem[0] = Sn_de[i];
}
}
/*---------------------------------------------------------------------------*\
hanning_window()
Hanning windows a frame of speech samples.
\*---------------------------------------------------------------------------*/
void hanning_window(
float Sn[], /* input frame of speech samples */
float Wn[], /* output frame of windowed samples */
int Nsam /* number of samples */
)
{
int i; /* loop variable */
for(i=0; i<Nsam; i++)
Wn[i] = Sn[i]*(0.5 - 0.5*cosf(2*PI*(float)i/(Nsam-1)));
}
/*---------------------------------------------------------------------------*\
autocorrelate()
Finds the first P autocorrelation values of an array of windowed speech
samples Sn[].
\*---------------------------------------------------------------------------*/
void autocorrelate(
float Sn[], /* frame of Nsam windowed speech samples */
float Rn[], /* array of P+1 autocorrelation coefficients */
int Nsam, /* number of windowed samples to use */
int order /* order of LPC analysis */
)
{
int i,j; /* loop variables */
for(j=0; j<order+1; j++) {
Rn[j] = 0.0;
for(i=0; i<Nsam-j; i++)
Rn[j] += Sn[i]*Sn[i+j];
}
}
/*---------------------------------------------------------------------------*\
levinson_durbin()
Given P+1 autocorrelation coefficients, finds P Linear Prediction Coeff.
(LPCs) where P is the order of the LPC all-pole model. The Levinson-Durbin
algorithm is used, and is described in:
J. Makhoul
"Linear prediction, a tutorial review"
Proceedings of the IEEE
Vol-63, No. 4, April 1975
\*---------------------------------------------------------------------------*/
void levinson_durbin(
float R[], /* order+1 autocorrelation coeff */
float lpcs[], /* order+1 LPC's */
int order /* order of the LPC analysis */
)
{
float a[order+1][order+1];
float sum, e, k;
int i,j; /* loop variables */
e = R[0]; /* Equation 38a, Makhoul */
for(i=1; i<=order; i++) {
sum = 0.0;
for(j=1; j<=i-1; j++)
sum += a[i-1][j]*R[i-j];
k = -1.0*(R[i] + sum)/e; /* Equation 38b, Makhoul */
if (fabsf(k) > 1.0)
k = 0.0;
a[i][i] = k;
for(j=1; j<=i-1; j++)
a[i][j] = a[i-1][j] + k*a[i-1][i-j]; /* Equation 38c, Makhoul */
e *= (1-k*k); /* Equation 38d, Makhoul */
}
for(i=1; i<=order; i++)
lpcs[i] = a[order][i];
lpcs[0] = 1.0;
}
/*---------------------------------------------------------------------------*\
inverse_filter()
Inverse Filter, A(z). Produces an array of residual samples from an array
of input samples and linear prediction coefficients.
The filter memory is stored in the first order samples of the input array.
\*---------------------------------------------------------------------------*/
void inverse_filter(
float Sn[], /* Nsam input samples */
float a[], /* LPCs for this frame of samples */
int Nsam, /* number of samples */
float res[], /* Nsam residual samples */
int order /* order of LPC */
)
{
int i,j; /* loop variables */
for(i=0; i<Nsam; i++) {
res[i] = 0.0;
for(j=0; j<=order; j++)
res[i] += Sn[i-j]*a[j];
}
}
/*---------------------------------------------------------------------------*\
synthesis_filter()
C version of the Speech Synthesis Filter, 1/A(z). Given an array of
residual or excitation samples, and the the LP filter coefficients, this
function will produce an array of speech samples. This filter structure is
IIR.
The synthesis filter has memory as well, this is treated in the same way
as the memory for the inverse filter (see inverse_filter() notes above).
The difference is that the memory for the synthesis filter is stored in
the output array, wheras the memory of the inverse filter is stored in the
input array.
Note: the calling function must update the filter memory.
\*---------------------------------------------------------------------------*/
void synthesis_filter(
float res[], /* Nsam input residual (excitation) samples */
float a[], /* LPCs for this frame of speech samples */
int Nsam, /* number of speech samples */
int order, /* LPC order */
float Sn_[] /* Nsam output synthesised speech samples */
)
{
int i,j; /* loop variables */
/* Filter Nsam samples */
for(i=0; i<Nsam; i++) {
Sn_[i] = res[i]*a[0];
for(j=1; j<=order; j++)
Sn_[i] -= Sn_[i-j]*a[j];
}
}
/*---------------------------------------------------------------------------*\
find_aks()
This function takes a frame of samples, and determines the linear
prediction coefficients for that frame of samples.
\*---------------------------------------------------------------------------*/
void find_aks(
float Sn[], /* Nsam samples with order sample memory */
float a[], /* order+1 LPCs with first coeff 1.0 */
int Nsam, /* number of input speech samples */
int order, /* order of the LPC analysis */
float *E /* residual energy */
)
{
float Wn[LPC_MAX_N]; /* windowed frame of Nsam speech samples */
float R[order+1]; /* order+1 autocorrelation values of Sn[] */
int i;
assert(Nsam < LPC_MAX_N);
hanning_window(Sn,Wn,Nsam);
autocorrelate(Wn,R,Nsam,order);
levinson_durbin(R,a,order);
*E = 0.0;
for(i=0; i<=order; i++)
*E += a[i]*R[i];
if (*E < 0.0)
*E = 1E-12;
}
/*---------------------------------------------------------------------------*\
weight()
Weights a vector of LPCs.
\*---------------------------------------------------------------------------*/
void weight(
float ak[], /* vector of order+1 LPCs */
float gamma, /* weighting factor */
int order, /* num LPCs (excluding leading 1.0) */
float akw[] /* weighted vector of order+1 LPCs */
)
{
int i;
for(i=1; i<=order; i++)
akw[i] = ak[i]*powf(gamma,(float)i);
}
+43
View File
@@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------*\
FILE........: lpc.h
AUTHOR......: David Rowe
DATE CREATED: 24/8/09
Linear Prediction functions written in C.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009-2012 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LPC__
#define __LPC__
#define LPC_MAX_ORDER 20
void pre_emp(float Sn_pre[], float Sn[], float *mem, int Nsam);
void de_emp(float Sn_se[], float Sn[], float *mem, int Nsam);
void hanning_window(float Sn[], float Wn[], int Nsam);
void autocorrelate(float Sn[], float Rn[], int Nsam, int order);
void levinson_durbin(float R[], float lpcs[], int order);
void inverse_filter(float Sn[], float a[], int Nsam, float res[], int order);
void synthesis_filter(float res[], float a[], int Nsam, int order, float Sn_[]);
void find_aks(float Sn[], float a[], int Nsam, int order, float *E);
void weight(float ak[], float gamma, int order, float akw[]);
#endif
+321
View File
@@ -0,0 +1,321 @@
/*---------------------------------------------------------------------------*\
FILE........: lsp.c
AUTHOR......: David Rowe
DATE CREATED: 24/2/93
This file contains functions for LPC to LSP conversion and LSP to
LPC conversion. Note that the LSP coefficients are not in radians
format but in the x domain of the unit circle.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "defines.h"
#include "lsp.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
/*---------------------------------------------------------------------------*\
Introduction to Line Spectrum Pairs (LSPs)
------------------------------------------
LSPs are used to encode the LPC filter coefficients {ak} for
transmission over the channel. LSPs have several properties (like
less sensitivity to quantisation noise) that make them superior to
direct quantisation of {ak}.
A(z) is a polynomial of order lpcrdr with {ak} as the coefficients.
A(z) is transformed to P(z) and Q(z) (using a substitution and some
algebra), to obtain something like:
A(z) = 0.5[P(z)(z+z^-1) + Q(z)(z-z^-1)] (1)
As you can imagine A(z) has complex zeros all over the z-plane. P(z)
and Q(z) have the very neat property of only having zeros _on_ the
unit circle. So to find them we take a test point z=exp(jw) and
evaluate P (exp(jw)) and Q(exp(jw)) using a grid of points between 0
and pi.
The zeros (roots) of P(z) also happen to alternate, which is why we
swap coefficients as we find roots. So the process of finding the
LSP frequencies is basically finding the roots of 5th order
polynomials.
The root so P(z) and Q(z) occur in symmetrical pairs at +/-w, hence
the name Line Spectrum Pairs (LSPs).
To convert back to ak we just evaluate (1), "clocking" an impulse
thru it lpcrdr times gives us the impulse response of A(z) which is
{ak}.
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
FUNCTION....: cheb_poly_eva()
AUTHOR......: David Rowe
DATE CREATED: 24/2/93
This function evalutes a series of chebyshev polynomials
FIXME: performing memory allocation at run time is very inefficient,
replace with stack variables of MAX_P size.
\*---------------------------------------------------------------------------*/
static float
cheb_poly_eva(float *coef,float x,int order)
/* float coef[] coefficients of the polynomial to be evaluated */
/* float x the point where polynomial is to be evaluated */
/* int order order of the polynomial */
{
int i;
float *t,*u,*v,sum;
float T[(order / 2) + 1];
/* Initialise pointers */
t = T; /* T[i-2] */
*t++ = 1.0;
u = t--; /* T[i-1] */
*u++ = x;
v = u--; /* T[i] */
/* Evaluate chebyshev series formulation using iterative approach */
for(i=2;i<=order/2;i++)
*v++ = (2*x)*(*u++) - *t++; /* T[i] = 2*x*T[i-1] - T[i-2] */
sum=0.0; /* initialise sum to zero */
t = T; /* reset pointer */
/* Evaluate polynomial and return value also free memory space */
for(i=0;i<=order/2;i++)
sum+=coef[(order/2)-i]**t++;
return sum;
}
/*---------------------------------------------------------------------------*\
FUNCTION....: lpc_to_lsp()
AUTHOR......: David Rowe
DATE CREATED: 24/2/93
This function converts LPC coefficients to LSP coefficients.
\*---------------------------------------------------------------------------*/
int lpc_to_lsp (float *a, int order, float *freq, int nb, float delta)
/* float *a lpc coefficients */
/* int order order of LPC coefficients (10) */
/* float *freq LSP frequencies in radians */
/* int nb number of sub-intervals (4) */
/* float delta grid spacing interval (0.02) */
{
float psuml,psumr,psumm,temp_xr,xl,xr,xm = 0;
float temp_psumr;
int i,j,m,flag,k;
float *px; /* ptrs of respective P'(z) & Q'(z) */
float *qx;
float *p;
float *q;
float *pt; /* ptr used for cheb_poly_eval()
whether P' or Q' */
int roots=0; /* number of roots found */
float Q[order + 1];
float P[order + 1];
flag = 1;
m = order/2; /* order of P'(z) & Q'(z) polynimials */
/* Allocate memory space for polynomials */
/* determine P'(z)'s and Q'(z)'s coefficients where
P'(z) = P(z)/(1 + z^(-1)) and Q'(z) = Q(z)/(1-z^(-1)) */
px = P; /* initilaise ptrs */
qx = Q;
p = px;
q = qx;
*px++ = 1.0;
*qx++ = 1.0;
for(i=1;i<=m;i++){
*px++ = a[i]+a[order+1-i]-*p++;
*qx++ = a[i]-a[order+1-i]+*q++;
}
px = P;
qx = Q;
for(i=0;i<m;i++){
*px = 2**px;
*qx = 2**qx;
px++;
qx++;
}
px = P; /* re-initialise ptrs */
qx = Q;
/* Search for a zero in P'(z) polynomial first and then alternate to Q'(z).
Keep alternating between the two polynomials as each zero is found */
xr = 0; /* initialise xr to zero */
xl = 1.0; /* start at point xl = 1 */
for(j=0;j<order;j++){
if(j%2) /* determines whether P' or Q' is eval. */
pt = qx;
else
pt = px;
psuml = cheb_poly_eva(pt,xl,order); /* evals poly. at xl */
flag = 1;
while(flag && (xr >= -1.0)){
xr = xl - delta ; /* interval spacing */
psumr = cheb_poly_eva(pt,xr,order);/* poly(xl-delta_x) */
temp_psumr = psumr;
temp_xr = xr;
/* if no sign change increment xr and re-evaluate
poly(xr). Repeat til sign change. if a sign change has
occurred the interval is bisected and then checked again
for a sign change which determines in which interval the
zero lies in. If there is no sign change between poly(xm)
and poly(xl) set interval between xm and xr else set
interval between xl and xr and repeat till root is located
within the specified limits */
if(((psumr*psuml)<0.0) || (psumr == 0.0)){
roots++;
psumm=psuml;
for(k=0;k<=nb;k++){
xm = (xl+xr)/2; /* bisect the interval */
psumm=cheb_poly_eva(pt,xm,order);
if(psumm*psuml>0.){
psuml=psumm;
xl=xm;
}
else{
psumr=psumm;
xr=xm;
}
}
/* once zero is found, reset initial interval to xr */
freq[j] = (xm);
xl = xm;
flag = 0; /* reset flag for next search */
}
else{
psuml=temp_psumr;
xl=temp_xr;
}
}
}
/* convert from x domain to radians */
for(i=0; i<order; i++) {
freq[i] = acosf(freq[i]);
}
return(roots);
}
/*---------------------------------------------------------------------------*\
FUNCTION....: lsp_to_lpc()
AUTHOR......: David Rowe
DATE CREATED: 24/2/93
This function converts LSP coefficients to LPC coefficients. In the
Speex code we worked out a way to simplify this significantly.
\*---------------------------------------------------------------------------*/
void lsp_to_lpc(float *lsp, float *ak, int order)
/* float *freq array of LSP frequencies in radians */
/* float *ak array of LPC coefficients */
/* int order order of LPC coefficients */
{
int i,j;
float xout1,xout2,xin1,xin2;
float *pw,*n1,*n2,*n3,*n4 = 0;
float freq[order];
float Wp[(order * 4) + 2];
/* convert from radians to the x=cos(w) domain */
for(i=0; i<order; i++)
freq[i] = cosf(lsp[i]);
pw = Wp;
/* initialise contents of array */
for(i=0;i<=4*(order/2)+1;i++){ /* set contents of buffer to 0 */
*pw++ = 0.0;
}
/* Set pointers up */
pw = Wp;
xin1 = 1.0;
xin2 = 1.0;
/* reconstruct P(z) and Q(z) by cascading second order polynomials
in form 1 - 2xz(-1) +z(-2), where x is the LSP coefficient */
for(j=0;j<=order;j++){
for(i=0;i<(order/2);i++){
n1 = pw+(i*4);
n2 = n1 + 1;
n3 = n2 + 1;
n4 = n3 + 1;
xout1 = xin1 - 2*(freq[2*i]) * *n1 + *n2;
xout2 = xin2 - 2*(freq[2*i+1]) * *n3 + *n4;
*n2 = *n1;
*n4 = *n3;
*n1 = xin1;
*n3 = xin2;
xin1 = xout1;
xin2 = xout2;
}
xout1 = xin1 + *(n4+1);
xout2 = xin2 - *(n4+2);
ak[j] = (xout1 + xout2)*0.5;
*(n4+1) = xin1;
*(n4+2) = xin2;
xin1 = 0.0;
xin2 = 0.0;
}
}
+37
View File
@@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------*\
FILE........: lsp.c
AUTHOR......: David Rowe
DATE CREATED: 24/2/93
This file contains functions for LPC to LSP conversion and LSP to
LPC conversion. Note that the LSP coefficients are not in radians
format but in the x domain of the unit circle.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LSP__
#define __LSP__
int lpc_to_lsp (float *a, int lpcrdr, float *freq, int nb, float delta);
void lsp_to_lpc(float *freq, float *ak, int lpcrdr);
#endif
+52
View File
@@ -0,0 +1,52 @@
/*---------------------------------------------------------------------------*\
FILE........: machdep.h
AUTHOR......: David Rowe
DATE CREATED: May 2 2013
Machine dependant functions, e.g. profiling that requires access to a clock
counter register.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2013 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MACHDEP__
#define __MACHDEP__
#ifdef PROFILE
#define PROFILE_VAR(...) unsigned int __VA_ARGS__
#define PROFILE_SAMPLE(timestamp) timestamp = machdep_profile_sample()
#define PROFILE_SAMPLE_AND_LOG(timestamp, prev_timestamp, label) \
timestamp = machdep_profile_sample_and_log(prev_timestamp, label)
#define PROFILE_SAMPLE_AND_LOG2(prev_timestamp, label) \
machdep_profile_sample_and_log(prev_timestamp, label)
#else
#define PROFILE_VAR(...)
#define PROFILE_SAMPLE(timestamp)
#define PROFILE_SAMPLE_AND_LOG(timestamp, prev_timestamp, label)
#define PROFILE_SAMPLE_AND_LOG2(prev_timestamp, label)
#endif
void machdep_profile_init(void);
void machdep_profile_reset(void);
unsigned int machdep_profile_sample(void);
unsigned int machdep_profile_sample_and_log(unsigned int start, char s[]);
void machdep_profile_print_logged_samples(void);
#endif
+142
View File
@@ -0,0 +1,142 @@
/*---------------------------------------------------------------------------*\
FILE........: mbest.c
AUTHOR......: David Rowe
DATE CREATED: Jan 2017
Multistage vector quantiser search algorithm that keeps multiple
candidates from each stage.
\*---------------------------------------------------------------------------*/
/*
Copyright David Rowe 2017
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mbest.h"
struct MBEST *mbest_create(int entries) {
int i,j;
struct MBEST *mbest;
assert(entries > 0);
mbest = (struct MBEST *)malloc(sizeof(struct MBEST));
assert(mbest != NULL);
mbest->entries = entries;
mbest->list = (struct MBEST_LIST *)malloc(entries*sizeof(struct MBEST_LIST));
assert(mbest->list != NULL);
for(i=0; i<mbest->entries; i++) {
for(j=0; j<MBEST_STAGES; j++)
mbest->list[i].index[j] = 0;
mbest->list[i].error = 1E32;
}
return mbest;
}
void mbest_destroy(struct MBEST *mbest) {
assert(mbest != NULL);
free(mbest->list);
free(mbest);
}
/*---------------------------------------------------------------------------*\
mbest_insert
Insert the results of a vector to codebook entry comparison. The
list is ordered in order or error, so those entries with the
smallest error will be first on the list.
\*---------------------------------------------------------------------------*/
void mbest_insert(struct MBEST *mbest, int index[], float error) {
int i, j, found;
struct MBEST_LIST *list = mbest->list;
int entries = mbest->entries;
found = 0;
for(i=0; i<entries && !found; i++)
if (error < list[i].error) {
found = 1;
for(j=entries-1; j>i; j--)
list[j] = list[j-1];
for(j=0; j<MBEST_STAGES; j++)
list[i].index[j] = index[j];
list[i].error = error;
}
}
#ifdef MBEST_PRINT_OUT
static void mbest_print(char title[], struct MBEST *mbest) {
int i,j;
fprintf(stderr, "%s\n", title);
for(i=0; i<mbest->entries; i++) {
for(j=0; j<MBEST_STAGES; j++)
fprintf(stderr, " %4d ", mbest->list[i].index[j]);
fprintf(stderr, " %f\n", mbest->list[i].error);
}
}
#endif
/*---------------------------------------------------------------------------*\
mbest_search
Searches vec[] to a codebbook of vectors, and maintains a list of the mbest
closest matches.
\*---------------------------------------------------------------------------*/
void mbest_search(
const float *cb, /* VQ codebook to search */
float vec[], /* target vector */
float w[], /* weighting vector */
int k, /* dimension of vector */
int m, /* number on entries in codebook */
struct MBEST *mbest, /* list of closest matches */
int index[] /* indexes that lead us here */
)
{
float e;
int i,j;
float diff;
for(j=0; j<m; j++) {
e = 0.0;
for(i=0; i<k; i++) {
diff = cb[j*k+i]-vec[i];
e += powf(diff*w[i],2.0);
}
index[0] = j;
mbest_insert(mbest, index, e);
}
}
+58
View File
@@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------*\
FILE........: mbest.h
AUTHOR......: David Rowe
DATE CREATED: Jan 2017
Multistage vector quantiser search algorithm that keeps multiple
candidates from each stage.
\*---------------------------------------------------------------------------*/
/*
Copyright David Rowe 2017
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MBEST__
#define __MBEST__
#define MBEST_STAGES 4
struct MBEST_LIST {
int index[MBEST_STAGES]; /* index of each stage that lead us to this error */
float error;
};
struct MBEST {
int entries; /* number of entries in mbest list */
struct MBEST_LIST *list;
};
struct MBEST *mbest_create(int entries);
void mbest_destroy(struct MBEST *mbest);
void mbest_insert(struct MBEST *mbest, int index[], float error);
void mbest_search(const float *cb, float vec[], float w[], int k, int m, struct MBEST *mbest, int index[]);
// #define MBEST_PRINT_OUT
#ifdef MBEST_PRINT_OUT
#define MBEST_PRINT(a,b) mbest_print((a),(b))
#else
#define MBEST_PRINT(a,b)
#endif
#endif
+115
View File
@@ -0,0 +1,115 @@
/*---------------------------------------------------------------------------*\
FILE........: modem_probe.h
AUTHOR......: Brady O'Brien
DATE CREATED: 9 January 2016
Library to easily extract debug traces from modems during development
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2016 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MODEMPROBE_H
#define __MODEMPROBE_H
#include <stdint.h>
#include <stdlib.h>
#include "comp.h"
#ifdef MODEMPROBE_ENABLE
/* Internal functions */
void modem_probe_init_int(char *modname, char *runname);
void modem_probe_close_int();
void modem_probe_samp_i_int(char * tracename,int samp[],size_t cnt);
void modem_probe_samp_f_int(char * tracename,float samp[],size_t cnt);
void modem_probe_samp_c_int(char * tracename,COMP samp[],size_t cnt);
/*
* Init the probe library.
* char *modname - Name of the modem under test
* char *runname - Name/path of the file data is dumped to
*/
static inline void modem_probe_init(char *modname,char *runname){
modem_probe_init_int(modname,runname);
}
/*
* Dump traces to a file and clean up
*/
static inline void modem_probe_close(){
modem_probe_close_int();
}
/*
* Save some number of int samples to a named trace
* char *tracename - name of trace being saved to
* int samp[] - int samples
* size_t cnt - how many samples to save
*/
static inline void modem_probe_samp_i(char *tracename,int samp[],size_t cnt){
modem_probe_samp_i_int(tracename,samp,cnt);
}
/*
* Save some number of float samples to a named trace
* char *tracename - name of trace being saved to
* float samp[] - int samples
* size_t cnt - how many samples to save
*/
static inline void modem_probe_samp_f(char *tracename,float samp[],size_t cnt){
modem_probe_samp_f_int(tracename,samp,cnt);
}
/*
* Save some number of complex samples to a named trace
* char *tracename - name of trace being saved to
* COMP samp[] - int samples
* size_t cnt - how many samples to save
*/
static inline void modem_probe_samp_c(char *tracename,COMP samp[],size_t cnt){
modem_probe_samp_c_int(tracename,samp,cnt);
}
#else
static inline void modem_probe_init(char *modname,char *runname){
return;
}
static inline void modem_probe_close(){
return;
}
static inline void modem_probe_samp_i(char *name,int samp[],size_t sampcnt){
return;
}
static inline void modem_probe_samp_f(char *name,float samp[],size_t cnt){
return;
}
static inline void modem_probe_samp_c(char *name,COMP samp[],size_t cnt){
return;
}
#endif
#endif
+75
View File
@@ -0,0 +1,75 @@
/*---------------------------------------------------------------------------*\
FILE........: modem_stats.h
AUTHOR......: David Rowe
DATE CREATED: June 2015
Common structure for returning demod stats from fdmdv and cohpsk modems.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2015 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __MODEM_STATS__
#define __MODEM_STATS__
#include "comp.h"
#include "kiss_fft.h"
#define MODEM_STATS_NC_MAX 20
#define MODEM_STATS_NR_MAX 6
#define MODEM_STATS_ET_MAX 8
#define MODEM_STATS_NSPEC 512
#define MODEM_STATS_MAX_F_HZ 4000
struct MODEM_STATS {
int Nc;
float snr_est; /* estimated SNR of rx signal in dB (3 kHz noise BW) */
COMP rx_symbols[MODEM_STATS_NR_MAX][MODEM_STATS_NC_MAX+1];
/* latest received symbols, for scatter plot */
int nr; /* number of rows in rx_symbols */
int sync; /* demod sync state */
float foff; /* estimated freq offset in Hz */
float rx_timing; /* estimated optimum timing offset in samples */
float clock_offset; /* Estimated tx/rx sample clock offset in ppm */
/* eye diagram traces */
/* Eye diagram plot -- first dim is trace number, second is the trace idx */
float rx_eye[MODEM_STATS_ET_MAX][80];
int neyetr; /* How many eye traces are plotted */
int neyesamp; /* How many samples in the eye diagram */
/* Buf for FFT/waterfall */
float fft_buf[2*MODEM_STATS_NSPEC];
kiss_fft_cfg fft_cfg;
};
void modem_stats_open(struct MODEM_STATS *f);
void modem_stats_close(struct MODEM_STATS *f);
void modem_stats_get_rx_spectrum(struct MODEM_STATS *f, float mag_spec_dB[], COMP rx_fdm[], int nin);
#endif
#ifdef __cplusplus
}
#endif
+93
View File
@@ -0,0 +1,93 @@
/*
FILE...: mpdecode_core.h
AUTHOR.: David Rowe
CREATED: Sep 2016
C-callable core functions for MpDecode, so they can be used for
Octave and C programs. Also some convenience functions to help use
the C-callable LDPC decoder in C programs.
*/
#ifndef __MPDECODE_CORE__
#define __MPDECODE_CORE__
struct LDPC {
int max_iter;
int dec_type;
int q_scale_factor;
int r_scale_factor;
int CodeLength;
int NumberParityBits;
int NumberRowsHcols;
int max_row_weight;
int max_col_weight;
double *H_rows;
double *H_cols;
};
int run_ldpc_decoder(struct LDPC *ldpc, char out_char[], double input[]);
void sd_to_llr(double llr[], double sd[], int n);
struct v_node {
int degree;
float initial_value;
int *index; /* the index of a c_node it is connected to */
int *socket; /* socket number at the c_node */
float *message;
int *sign;
};
struct c_node {
int degree;
int *index;
float *message;
int *socket; /* socket number at the v_node */
};
void init_c_v_nodes(struct c_node *c_nodes,
int shift,
int NumberParityBits,
int max_row_weight,
double *H_rows,
int H1,
int CodeLength,
struct v_node *v_nodes,
int NumberRowsHcols,
double *H_cols,
int max_col_weight,
int dec_type,
double *input);
void ApproximateMinStar( int BitErrors[],
int DecodedBits[],
struct c_node c_nodes[],
struct v_node v_nodes[],
int CodeLength,
int NumberParityBits,
int max_iter );
void MinSum( int BitErrors[],
int DecodedBits[],
struct c_node c_nodes[],
struct v_node v_nodes[],
int CodeLength,
int NumberParityBits,
int max_iter,
float r_scale_factor,
float q_scale_factor,
int data[] );
void SumProduct( int BitErrors[],
int DecodedBits[],
struct c_node c_nodes[],
struct v_node v_nodes[],
int CodeLength,
int NumberParityBits,
int max_iter,
float r_scale_factor,
float q_scale_factor,
int data[]);
#endif
+702
View File
@@ -0,0 +1,702 @@
/*---------------------------------------------------------------------------*\
FILE........: nlp.c
AUTHOR......: David Rowe
DATE CREATED: 23/3/93
Non Linear Pitch (NLP) estimation functions.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "defines.h"
#include "nlp.h"
#include "dump.h"
#include "codec2_fft.h"
#undef PROFILE
#include "machdep.h"
#include "os.h"
#include <assert.h>
#include <math.h>
#include <stdlib.h>
/*---------------------------------------------------------------------------*\
DEFINES
\*---------------------------------------------------------------------------*/
#define PMAX_M 320 /* maximum NLP analysis window size */
#define COEFF 0.95 /* notch filter parameter */
#define PE_FFT_SIZE 512 /* DFT size for pitch estimation */
#define DEC 5 /* decimation factor */
#define SAMPLE_RATE 8000
#define PI 3.141592654 /* mathematical constant */
#define T 0.1 /* threshold for local minima candidate */
#define F0_MAX 500
#define CNLP 0.3 /* post processor constant */
#define NLP_NTAP 48 /* Decimation LPF order */
#undef POST_PROCESS_MBE /* choose post processor */
/* 8 to 16 kHz sample rate conversion */
#define FDMDV_OS 2 /* oversampling rate */
#define FDMDV_OS_TAPS_16K 48 /* number of OS filter taps at 16kHz */
#define FDMDV_OS_TAPS_8K (FDMDV_OS_TAPS_16K/FDMDV_OS) /* number of OS filter taps at 8kHz */
/*---------------------------------------------------------------------------*\
GLOBALS
\*---------------------------------------------------------------------------*/
/* 48 tap 600Hz low pass FIR filter coefficients */
const float nlp_fir[] = {
-1.0818124e-03,
-1.1008344e-03,
-9.2768838e-04,
-4.2289438e-04,
5.5034190e-04,
2.0029849e-03,
3.7058509e-03,
5.1449415e-03,
5.5924666e-03,
4.3036754e-03,
8.0284511e-04,
-4.8204610e-03,
-1.1705810e-02,
-1.8199275e-02,
-2.2065282e-02,
-2.0920610e-02,
-1.2808831e-02,
3.2204775e-03,
2.6683811e-02,
5.5520624e-02,
8.6305944e-02,
1.1480192e-01,
1.3674206e-01,
1.4867556e-01,
1.4867556e-01,
1.3674206e-01,
1.1480192e-01,
8.6305944e-02,
5.5520624e-02,
2.6683811e-02,
3.2204775e-03,
-1.2808831e-02,
-2.0920610e-02,
-2.2065282e-02,
-1.8199275e-02,
-1.1705810e-02,
-4.8204610e-03,
8.0284511e-04,
4.3036754e-03,
5.5924666e-03,
5.1449415e-03,
3.7058509e-03,
2.0029849e-03,
5.5034190e-04,
-4.2289438e-04,
-9.2768838e-04,
-1.1008344e-03,
-1.0818124e-03
};
typedef struct {
int Fs; /* sample rate in Hz */
int m;
float w[PMAX_M/DEC]; /* DFT window */
float sq[PMAX_M]; /* squared speech samples */
float mem_x,mem_y; /* memory for notch filter */
float mem_fir[NLP_NTAP]; /* decimation FIR filter memory */
codec2_fft_cfg fft_cfg; /* kiss FFT config */
float *Sn16k; /* Fs=16kHz input speech vector */
FILE *f;
} NLP;
#ifdef POST_PROCESS_MBE
float test_candidate_mbe(COMP Sw[], COMP W[], float f0);
float post_process_mbe(COMP Fw[], int pmin, int pmax, float gmax, COMP Sw[], COMP W[], float *prev_Wo);
#endif
float post_process_sub_multiples(COMP Fw[],
int pmin, int pmax, float gmax, int gmax_bin,
float *prev_f0);
static void fdmdv_16_to_8(float out8k[], float in16k[], int n);
/*---------------------------------------------------------------------------*\
nlp_create()
Initialisation function for NLP pitch estimator.
\*---------------------------------------------------------------------------*/
void *nlp_create(C2CONST *c2const)
{
NLP *nlp;
int i;
int m = c2const->m_pitch;
int Fs = c2const->Fs;
nlp = (NLP*)malloc(sizeof(NLP));
if (nlp == NULL)
return NULL;
assert((Fs == 8000) || (Fs == 16000));
nlp->Fs = Fs;
nlp->m = m;
/* if running at 16kHz allocate storage for decimating filter memory */
if (Fs == 16000) {
nlp->Sn16k = (float*)malloc(sizeof(float)*(FDMDV_OS_TAPS_16K + c2const->n_samp));
for(i=0; i<FDMDV_OS_TAPS_16K; i++) {
nlp->Sn16k[i] = 0.0;
}
if (nlp->Sn16k == NULL) {
free(nlp);
return NULL;
}
/* most processing occurs at 8 kHz sample rate so halve m */
m /= 2;
}
assert(m <= PMAX_M);
for(i=0; i<m/DEC; i++) {
nlp->w[i] = 0.5 - 0.5*cosf(2*PI*i/(m/DEC-1));
}
for(i=0; i<PMAX_M; i++)
nlp->sq[i] = 0.0;
nlp->mem_x = 0.0;
nlp->mem_y = 0.0;
for(i=0; i<NLP_NTAP; i++)
nlp->mem_fir[i] = 0.0;
nlp->fft_cfg = codec2_fft_alloc (PE_FFT_SIZE, 0, NULL, NULL);
assert(nlp->fft_cfg != NULL);
return (void*)nlp;
}
/*---------------------------------------------------------------------------*\
nlp_destroy()
Shut down function for NLP pitch estimator.
\*---------------------------------------------------------------------------*/
void nlp_destroy(void *nlp_state)
{
NLP *nlp;
assert(nlp_state != NULL);
nlp = (NLP*)nlp_state;
codec2_fft_free(nlp->fft_cfg);
if (nlp->Fs == 16000) {
free(nlp->Sn16k);
}
free(nlp_state);
}
/*---------------------------------------------------------------------------*\
nlp()
Determines the pitch in samples using the Non Linear Pitch (NLP)
algorithm [1]. Returns the fundamental in Hz. Note that the actual
pitch estimate is for the centre of the M sample Sn[] vector, not
the current N sample input vector. This is (I think) a delay of 2.5
frames with N=80 samples. You should align further analysis using
this pitch estimate to be centred on the middle of Sn[].
Two post processors have been tried, the MBE version (as discussed
in [1]), and a post processor that checks sub-multiples. Both
suffer occasional gross pitch errors (i.e. neither are perfect). In
the presence of background noise the sub-multiple algorithm tends
towards low F0 which leads to better sounding background noise than
the MBE post processor.
A good way to test and develop the NLP pitch estimator is using the
tnlp (codec2/unittest) and the codec2/octave/plnlp.m Octave script.
A pitch tracker searching a few frames forward and backward in time
would be a useful addition.
References:
[1] http://rowetel.com/downloads/1997_rowe_phd_thesis.pdf Chapter 4
\*---------------------------------------------------------------------------*/
float nlp(
void *nlp_state,
float Sn[], /* input speech vector */
int n, /* frames shift (no. new samples in Sn[]) */
float *pitch, /* estimated pitch period in samples at current Fs */
COMP Sw[], /* Freq domain version of Sn[] */
COMP W[], /* Freq domain window */
float *prev_f0 /* previous pitch f0 in Hz, memory for pitch tracking */
)
{
NLP *nlp;
float notch; /* current notch filter output */
COMP Fw[PE_FFT_SIZE]; /* DFT of squared signal (input/output) */
float gmax;
int gmax_bin;
int m, i, j;
float best_f0;
PROFILE_VAR(start, tnotch, filter, peakpick, window, fft, magsq, shiftmem);
assert(nlp_state != NULL);
nlp = (NLP*)nlp_state;
m = nlp->m;
/* Square, notch filter at DC, and LP filter vector */
/* If running at 16 kHz decimate to 8 kHz, as NLP ws designed for
Fs = 8kHz. The decimating filter introduces about 3ms of delay,
that shouldn't be a problem as pitch changes slowly. */
if (nlp->Fs == 8000) {
/* Square latest input samples */
for(i=m-n; i<m; i++) {
nlp->sq[i] = Sn[i]*Sn[i];
}
}
else {
assert(nlp->Fs == 16000);
/* re-sample at 8 KHz */
for(i=0; i<n; i++) {
nlp->Sn16k[FDMDV_OS_TAPS_16K+i] = Sn[m-n+i];
}
m /= 2; n /= 2;
float Sn8k[n];
fdmdv_16_to_8(Sn8k, &nlp->Sn16k[FDMDV_OS_TAPS_16K], n);
/* Square latest input samples */
for(i=m-n, j=0; i<m; i++, j++) {
nlp->sq[i] = Sn8k[j]*Sn8k[j];
}
assert(j <= n);
}
//fprintf(stderr, "n: %d m: %d\n", n, m);
PROFILE_SAMPLE(start);
for(i=m-n; i<m; i++) { /* notch filter at DC */
notch = nlp->sq[i] - nlp->mem_x;
notch += COEFF*nlp->mem_y;
nlp->mem_x = nlp->sq[i];
nlp->mem_y = notch;
nlp->sq[i] = notch + 1.0; /* With 0 input vectors to codec,
kiss_fft() would take a long
time to execute when running in
real time. Problem was traced
to kiss_fft function call in
this function. Adding this small
constant fixed problem. Not
exactly sure why. */
}
PROFILE_SAMPLE_AND_LOG(tnotch, start, " square and notch");
for(i=m-n; i<m; i++) { /* FIR filter vector */
for(j=0; j<NLP_NTAP-1; j++)
nlp->mem_fir[j] = nlp->mem_fir[j+1];
nlp->mem_fir[NLP_NTAP-1] = nlp->sq[i];
nlp->sq[i] = 0.0;
for(j=0; j<NLP_NTAP; j++)
nlp->sq[i] += nlp->mem_fir[j]*nlp_fir[j];
}
PROFILE_SAMPLE_AND_LOG(filter, tnotch, " filter");
/* Decimate and DFT */
for(i=0; i<PE_FFT_SIZE; i++) {
Fw[i].real = 0.0;
Fw[i].imag = 0.0;
}
for(i=0; i<m/DEC; i++) {
Fw[i].real = nlp->sq[i*DEC]*nlp->w[i];
}
PROFILE_SAMPLE_AND_LOG(window, filter, " window");
#ifdef DUMP
dump_dec(Fw);
#endif
// FIXME: check if this can be converted to a real fft
// since all imag inputs are 0
codec2_fft_inplace(nlp->fft_cfg, Fw);
PROFILE_SAMPLE_AND_LOG(fft, window, " fft");
for(i=0; i<PE_FFT_SIZE; i++)
Fw[i].real = Fw[i].real*Fw[i].real + Fw[i].imag*Fw[i].imag;
PROFILE_SAMPLE_AND_LOG(magsq, fft, " mag sq");
#ifdef DUMP
dump_sq(m, nlp->sq);
dump_Fw(Fw);
#endif
/* todo: express everything in f0, as pitch in samples is dep on Fs */
int pmin = floor(SAMPLE_RATE*P_MIN_S);
int pmax = floor(SAMPLE_RATE*P_MAX_S);
/* find global peak */
gmax = 0.0;
gmax_bin = PE_FFT_SIZE*DEC/pmax;
for(i=PE_FFT_SIZE*DEC/pmax; i<=PE_FFT_SIZE*DEC/pmin; i++) {
if (Fw[i].real > gmax) {
gmax = Fw[i].real;
gmax_bin = i;
}
}
PROFILE_SAMPLE_AND_LOG(peakpick, magsq, " peak pick");
#ifdef POST_PROCESS_MBE
best_f0 = post_process_mbe(Fw, pmin, pmax, gmax, Sw, W, prev_f0);
#else
best_f0 = post_process_sub_multiples(Fw, pmin, pmax, gmax, gmax_bin, prev_f0);
#endif
PROFILE_SAMPLE_AND_LOG(shiftmem, peakpick, " post process");
/* Shift samples in buffer to make room for new samples */
for(i=0; i<m-n; i++)
nlp->sq[i] = nlp->sq[i+n];
/* return pitch period in samples and F0 estimate */
*pitch = (float)nlp->Fs/best_f0;
PROFILE_SAMPLE_AND_LOG2(shiftmem, " shift mem");
PROFILE_SAMPLE_AND_LOG2(start, " nlp int");
*prev_f0 = best_f0;
return(best_f0);
}
/*---------------------------------------------------------------------------*\
post_process_sub_multiples()
Given the global maximma of Fw[] we search integer submultiples for
local maxima. If local maxima exist and they are above an
experimentally derived threshold (OK a magic number I pulled out of
the air) we choose the submultiple as the F0 estimate.
The rational for this is that the lowest frequency peak of Fw[]
should be F0, as Fw[] can be considered the autocorrelation function
of Sw[] (the speech spectrum). However sometimes due to phase
effects the lowest frequency maxima may not be the global maxima.
This works OK in practice and favours low F0 values in the presence
of background noise which means the sinusoidal codec does an OK job
of synthesising the background noise. High F0 in background noise
tends to sound more periodic introducing annoying artifacts.
\*---------------------------------------------------------------------------*/
float post_process_sub_multiples(COMP Fw[],
int pmin, int pmax, float gmax, int gmax_bin,
float *prev_f0)
{
int min_bin, cmax_bin;
int mult;
float thresh, best_f0;
int b, bmin, bmax, lmax_bin;
float lmax;
int prev_f0_bin;
/* post process estimate by searching submultiples */
mult = 2;
min_bin = PE_FFT_SIZE*DEC/pmax;
cmax_bin = gmax_bin;
prev_f0_bin = *prev_f0*(PE_FFT_SIZE*DEC)/SAMPLE_RATE;
while(gmax_bin/mult >= min_bin) {
b = gmax_bin/mult; /* determine search interval */
bmin = 0.8*b;
bmax = 1.2*b;
if (bmin < min_bin)
bmin = min_bin;
/* lower threshold to favour previous frames pitch estimate,
this is a form of pitch tracking */
if ((prev_f0_bin > bmin) && (prev_f0_bin < bmax))
thresh = CNLP*0.5*gmax;
else
thresh = CNLP*gmax;
lmax = 0;
lmax_bin = bmin;
for (b=bmin; b<=bmax; b++) /* look for maximum in interval */
if (Fw[b].real > lmax) {
lmax = Fw[b].real;
lmax_bin = b;
}
if (lmax > thresh)
if ((lmax > Fw[lmax_bin-1].real) && (lmax > Fw[lmax_bin+1].real)) {
cmax_bin = lmax_bin;
}
mult++;
}
best_f0 = (float)cmax_bin*SAMPLE_RATE/(PE_FFT_SIZE*DEC);
return best_f0;
}
#ifdef POST_PROCESS_MBE
/*---------------------------------------------------------------------------*\
post_process_mbe()
Use the MBE pitch estimation algorithm to evaluate pitch candidates. This
works OK but the accuracy at low F0 is affected by NW, the analysis window
size used for the DFT of the input speech Sw[]. Also favours high F0 in
the presence of background noise which causes periodic artifacts in the
synthesised speech.
\*---------------------------------------------------------------------------*/
float post_process_mbe(COMP Fw[], int pmin, int pmax, float gmax, COMP Sw[], COMP W[], float *prev_Wo)
{
float candidate_f0;
float f0,best_f0; /* fundamental frequency */
float e,e_min; /* MBE cost function */
int i;
#ifdef DUMP
float e_hz[F0_MAX];
#endif
#if !defined(NDEBUG) || defined(DUMP)
int bin;
#endif
float f0_min, f0_max;
float f0_start, f0_end;
f0_min = (float)SAMPLE_RATE/pmax;
f0_max = (float)SAMPLE_RATE/pmin;
/* Now look for local maxima. Each local maxima is a candidate
that we test using the MBE pitch estimation algotithm */
#ifdef DUMP
for(i=0; i<F0_MAX; i++)
e_hz[i] = -1;
#endif
e_min = 1E32;
best_f0 = 50;
for(i=PE_FFT_SIZE*DEC/pmax; i<=PE_FFT_SIZE*DEC/pmin; i++) {
if ((Fw[i].real > Fw[i-1].real) && (Fw[i].real > Fw[i+1].real)) {
/* local maxima found, lets test if it's big enough */
if (Fw[i].real > T*gmax) {
/* OK, sample MBE cost function over +/- 10Hz range in 2.5Hz steps */
candidate_f0 = (float)i*SAMPLE_RATE/(PE_FFT_SIZE*DEC);
f0_start = candidate_f0-20;
f0_end = candidate_f0+20;
if (f0_start < f0_min) f0_start = f0_min;
if (f0_end > f0_max) f0_end = f0_max;
for(f0=f0_start; f0<=f0_end; f0+= 2.5) {
e = test_candidate_mbe(Sw, W, f0);
#if !defined(NDEBUG) || defined(DUMP)
bin = floorf(f0); assert((bin > 0) && (bin < F0_MAX));
#endif
#ifdef DUMP
e_hz[bin] = e;
#endif
if (e < e_min) {
e_min = e;
best_f0 = f0;
}
}
}
}
}
/* finally sample MBE cost function around previous pitch estimate
(form of pitch tracking) */
candidate_f0 = *prev_Wo * SAMPLE_RATE/TWO_PI;
f0_start = candidate_f0-20;
f0_end = candidate_f0+20;
if (f0_start < f0_min) f0_start = f0_min;
if (f0_end > f0_max) f0_end = f0_max;
for(f0=f0_start; f0<=f0_end; f0+= 2.5) {
e = test_candidate_mbe(Sw, W, f0);
#if !defined(NDEBUG) || defined(DUMP)
bin = floorf(f0); assert((bin > 0) && (bin < F0_MAX));
#endif
#ifdef DUMP
e_hz[bin] = e;
#endif
if (e < e_min) {
e_min = e;
best_f0 = f0;
}
}
#ifdef DUMP
dump_e(e_hz);
#endif
return best_f0;
}
/*---------------------------------------------------------------------------*\
test_candidate_mbe()
Returns the error of the MBE cost function for the input f0.
Note: I think a lot of the operations below can be simplified as
W[].imag = 0 and has been normalised such that den always equals 1.
\*---------------------------------------------------------------------------*/
float test_candidate_mbe(
COMP Sw[],
COMP W[],
float f0
)
{
COMP Sw_[FFT_ENC]; /* DFT of all voiced synthesised signal */
int l,al,bl,m; /* loop variables */
COMP Am; /* amplitude sample for this band */
int offset; /* centers Hw[] about current harmonic */
float den; /* denominator of Am expression */
float error; /* accumulated error between originl and synthesised */
float Wo; /* current "test" fundamental freq. */
int L;
L = floorf((SAMPLE_RATE/2.0)/f0);
Wo = f0*(2*PI/SAMPLE_RATE);
error = 0.0;
/* Just test across the harmonics in the first 1000 Hz (L/4) */
for(l=1; l<L/4; l++) {
Am.real = 0.0;
Am.imag = 0.0;
den = 0.0;
al = ceilf((l - 0.5)*Wo*FFT_ENC/TWO_PI);
bl = ceilf((l + 0.5)*Wo*FFT_ENC/TWO_PI);
/* Estimate amplitude of harmonic assuming harmonic is totally voiced */
for(m=al; m<bl; m++) {
offset = FFT_ENC/2 + m - l*Wo*FFT_ENC/TWO_PI + 0.5;
Am.real += Sw[m].real*W[offset].real + Sw[m].imag*W[offset].imag;
Am.imag += Sw[m].imag*W[offset].real - Sw[m].real*W[offset].imag;
den += W[offset].real*W[offset].real + W[offset].imag*W[offset].imag;
}
Am.real = Am.real/den;
Am.imag = Am.imag/den;
/* Determine error between estimated harmonic and original */
for(m=al; m<bl; m++) {
offset = FFT_ENC/2 + m - l*Wo*FFT_ENC/TWO_PI + 0.5;
Sw_[m].real = Am.real*W[offset].real - Am.imag*W[offset].imag;
Sw_[m].imag = Am.real*W[offset].imag + Am.imag*W[offset].real;
error += (Sw[m].real - Sw_[m].real)*(Sw[m].real - Sw_[m].real);
error += (Sw[m].imag - Sw_[m].imag)*(Sw[m].imag - Sw_[m].imag);
}
}
return error;
}
#endif
/*---------------------------------------------------------------------------*\
FUNCTION....: fdmdv_16_to_8()
AUTHOR......: David Rowe
DATE CREATED: 9 May 2012
Changes the sample rate of a signal from 16 to 8 kHz.
n is the number of samples at the 8 kHz rate, there are FDMDV_OS*n
samples at the 48 kHz rate. As above however a memory of
FDMDV_OS_TAPS samples is reqd for in16k[] (see t16_8.c unit test as example).
Low pass filter the 16 kHz signal at 4 kHz using the same filter as
the upsampler, then just output every FDMDV_OS-th filtered sample.
Note: this function copied from fdmdv.c, included in nlp.c as a convenience
to avoid linking with another source file.
\*---------------------------------------------------------------------------*/
static void fdmdv_16_to_8(float out8k[], float in16k[], int n)
{
float acc;
int i,j,k;
for(i=0, k=0; k<n; i+=FDMDV_OS, k++) {
acc = 0.0;
for(j=0; j<FDMDV_OS_TAPS_16K; j++)
acc += fdmdv_os_filter[j]*in16k[i-j];
out8k[k] = acc;
}
/* update filter memory */
for(i=-FDMDV_OS_TAPS_16K; i<0; i++)
in16k[i] = in16k[i + n*FDMDV_OS];
}
+38
View File
@@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------*\
FILE........: nlp.c
AUTHOR......: David Rowe
DATE CREATED: 23/3/93
Non Linear Pitch (NLP) estimation functions.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NLP__
#define __NLP__
#include "comp.h"
void *nlp_create(C2CONST *c2const);
void nlp_destroy(void *nlp_state);
float nlp(void *nlp_state, float Sn[], int n,
float *pitch_samples, COMP Sw[], COMP W[], float *prev_f0);
#endif
File diff suppressed because it is too large Load Diff
+39
View File
@@ -0,0 +1,39 @@
/*---------------------------------------------------------------------------*\
FILE........: octave.h
AUTHOR......: David Rowe
DATE CREATED: April 28 2012
Functions to save C arrays in Octave matrix format. the output text
file can be directly read into octave using "load filename".
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2012 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OCTAVE__
#define __OCTAVE__
#include "comp.h"
void octave_save_int(FILE *f, char name[], int data[], int rows, int cols);
void octave_save_float(FILE *f, char name[], float data[], int rows, int cols, int col_len);
void octave_save_complex(FILE *f, char name[], COMP data[], int rows, int cols, int col_len);
#endif
+103
View File
@@ -0,0 +1,103 @@
/*---------------------------------------------------------------------------*\
FILE........: ofdm_internal.h
AUTHORS.....: David Rowe & Steve Sampson
DATE CREATED: June 2017
OFDM Internal definitions.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2017 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OFDM_INTERNAL_H
#define OFDM_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <complex.h>
#include <stdbool.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846f /* math constant */
#endif
#define TAU (2.0f * M_PI) /* mathematical constant */
#define OFDM_NC 16
#define OFDM_TS 0.018f
#define OFDM_RS (1.0f / OFDM_TS)
#define OFDM_FS 8000.0f
#define OFDM_BPS 2
#define OFDM_TCP 0.002f
#define OFDM_NS 8
#define OFDM_CENTRE 1500.0f
/* To prevent C99 warning */
#define OFDM_M 144
#define OFDM_NCP 16
#ifdef OLD_STYLE
/* This will produce a warning in C99 as (int) makes these variable */
#define OFDM_M ((int)(OFDM_FS / OFDM_RS))
#define OFDM_NCP ((int)(OFDM_TCP * OFDM_FS))
#endif
#define OFDM_FTWINDOWWIDTH 11
#define OFDM_BITSPERFRAME ((OFDM_NS - 1) * (OFDM_NC * OFDM_BPS))
#define OFDM_ROWSPERFRAME (OFDM_BITSPERFRAME / (OFDM_NC * OFDM_BPS))
#define OFDM_SAMPLESPERFRAME (OFDM_NS * (OFDM_M + OFDM_NCP))
#define OFDM_MAX_SAMPLESPERFRAME (OFDM_SAMPLESPERFRAME + (OFDM_M + OFDM_NCP)/4)
#define OFDM_RXBUF (3 * OFDM_SAMPLESPERFRAME + 3 * (OFDM_M + OFDM_NCP))
struct OFDM {
float foff_est_gain;
float foff_est_hz;
int verbose;
int sample_point;
int timing_est;
int nin;
bool timing_en;
bool foff_est_en;
bool phase_est_en;
complex float pilot_samples[OFDM_M + OFDM_NCP];
complex float W[OFDM_NC + 2][OFDM_M];
complex float rxbuf[OFDM_RXBUF];
complex float pilots[OFDM_NC + 2];
float w[OFDM_NC + 2];
/* Demodulator data */
complex float rx_sym[OFDM_NS + 3][OFDM_NC + 2];
complex float rx_np[OFDM_ROWSPERFRAME * OFDM_NC];
float rx_amp[OFDM_ROWSPERFRAME * OFDM_NC];
float aphase_est_pilot_log[OFDM_ROWSPERFRAME * OFDM_NC];
};
#ifdef __cplusplus
}
#endif
#endif
+53
View File
@@ -0,0 +1,53 @@
/* Generate using fir1(47,1/2) in Octave */
static const float fdmdv_os_filter[]= {
-0.0008215855034550382,
-0.0007833023901802921,
0.001075563790768233,
0.001199092367787555,
-0.001765309502928316,
-0.002055372115328064,
0.002986877604154257,
0.003462567920638414,
-0.004856570111126334,
-0.005563143845031497,
0.007533613299748122,
0.008563932468880897,
-0.01126857129039911,
-0.01280782411693687,
0.01651443896361847,
0.01894875110322284,
-0.02421604439474981,
-0.02845107338464062,
0.03672973563400258,
0.04542046150312214,
-0.06189165826716491,
-0.08721876380763803,
0.1496157094199961,
0.4497962274137046,
0.4497962274137046,
0.1496157094199961,
-0.08721876380763803,
-0.0618916582671649,
0.04542046150312216,
0.03672973563400257,
-0.02845107338464062,
-0.02421604439474984,
0.01894875110322284,
0.01651443896361848,
-0.01280782411693687,
-0.0112685712903991,
0.008563932468880899,
0.007533613299748123,
-0.005563143845031501,
-0.004856570111126346,
0.003462567920638419,
0.002986877604154259,
-0.002055372115328063,
-0.001765309502928318,
0.001199092367787557,
0.001075563790768233,
-0.0007833023901802925,
-0.0008215855034550383
};
+140
View File
@@ -0,0 +1,140 @@
/*
Copyright (C) 2010 Perens LLC <bruce@perens.com>
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "defines.h"
#include "quantise.h"
#include <stdio.h>
/* Compile-time constants */
/* Size of unsigned char in bits. Assumes 8 bits-per-char. */
static const unsigned int WordSize = 8;
/* Mask to pick the bit component out of bitIndex. */
static const unsigned int IndexMask = 0x7;
/* Used to pick the word component out of bitIndex. */
static const unsigned int ShiftRight = 3;
/** Pack a bit field into a bit string, encoding the field in Gray code.
*
* The output is an array of unsigned char data. The fields are efficiently
* packed into the bit string. The Gray coding is a naive attempt to reduce
* the effect of single-bit errors, we expect to do a better job as the
* codec develops.
*
* This code would be simpler if it just set one bit at a time in the string,
* but would hit the same cache line more often. I'm not sure the complexity
* gains us anything here.
*
* Although field is currently of int type rather than unsigned for
* compatibility with the rest of the code, indices are always expected to
* be >= 0.
*/
void
pack(
unsigned char * bitArray, /* The output bit string. */
unsigned int * bitIndex, /* Index into the string in BITS, not bytes.*/
int field, /* The bit field to be packed. */
unsigned int fieldWidth/* Width of the field in BITS, not bytes. */
)
{
pack_natural_or_gray(bitArray, bitIndex, field, fieldWidth, 1);
}
void
pack_natural_or_gray(
unsigned char * bitArray, /* The output bit string. */
unsigned int * bitIndex, /* Index into the string in BITS, not bytes.*/
int field, /* The bit field to be packed. */
unsigned int fieldWidth,/* Width of the field in BITS, not bytes. */
unsigned int gray /* non-zero for gray coding */
)
{
if (gray) {
/* Convert the field to Gray code */
field = (field >> 1) ^ field;
}
do {
unsigned int bI = *bitIndex;
unsigned int bitsLeft = WordSize - (bI & IndexMask);
unsigned int sliceWidth =
bitsLeft < fieldWidth ? bitsLeft : fieldWidth;
unsigned int wordIndex = bI >> ShiftRight;
bitArray[wordIndex] |=
((unsigned char)((field >> (fieldWidth - sliceWidth))
<< (bitsLeft - sliceWidth)));
*bitIndex = bI + sliceWidth;
fieldWidth -= sliceWidth;
} while ( fieldWidth != 0 );
}
/** Unpack a field from a bit string, converting from Gray code to binary.
*
*/
int
unpack(
const unsigned char * bitArray, /* The input bit string. */
unsigned int * bitIndex, /* Index into the string in BITS, not bytes.*/
unsigned int fieldWidth/* Width of the field in BITS, not bytes. */
)
{
return unpack_natural_or_gray(bitArray, bitIndex, fieldWidth, 1);
}
/** Unpack a field from a bit string, to binary, optionally using
* natural or Gray code.
*
*/
int
unpack_natural_or_gray(
const unsigned char * bitArray, /* The input bit string. */
unsigned int * bitIndex, /* Index into the string in BITS, not bytes.*/
unsigned int fieldWidth,/* Width of the field in BITS, not bytes. */
unsigned int gray /* non-zero for Gray coding */
)
{
unsigned int field = 0;
unsigned int t;
do {
unsigned int bI = *bitIndex;
unsigned int bitsLeft = WordSize - (bI & IndexMask);
unsigned int sliceWidth =
bitsLeft < fieldWidth ? bitsLeft : fieldWidth;
field |= (((bitArray[bI >> ShiftRight] >> (bitsLeft - sliceWidth)) & ((1 << sliceWidth) - 1)) << (fieldWidth - sliceWidth));
*bitIndex = bI + sliceWidth;
fieldWidth -= sliceWidth;
} while ( fieldWidth != 0 );
if (gray) {
/* Convert from Gray code to binary. Works for maximum 8-bit fields. */
t = field ^ (field >> 8);
t ^= (t >> 4);
t ^= (t >> 2);
t ^= (t >> 1);
}
else {
t = field;
}
return t;
}
+289
View File
@@ -0,0 +1,289 @@
/*---------------------------------------------------------------------------*\
FILE........: phase.c
AUTHOR......: David Rowe
DATE CREATED: 1/2/09
Functions for modelling and synthesising phase.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not,see <http://www.gnu.org/licenses/>.
*/
#include "defines.h"
#include "phase.h"
#include "kiss_fft.h"
#include "comp.h"
#include "comp_prim.h"
#include "sine.h"
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
/*---------------------------------------------------------------------------*\
sample_phase()
Samples phase at centre of each harmonic from and array of FFT_ENC
DFT samples.
\*---------------------------------------------------------------------------*/
void sample_phase(MODEL *model,
COMP H[],
COMP A[] /* LPC analysis filter in freq domain */
)
{
int m, b;
float r;
r = TWO_PI/(FFT_ENC);
/* Sample phase at harmonics */
for(m=1; m<=model->L; m++) {
b = (int)(m*model->Wo/r + 0.5);
H[m] = cconj(A[b]); /* synth filter 1/A is opposite phase to analysis filter */
}
}
/*---------------------------------------------------------------------------*\
phase_synth_zero_order()
Synthesises phases based on SNR and a rule based approach. No phase
parameters are required apart from the SNR (which can be reduced to a
1 bit V/UV decision per frame).
The phase of each harmonic is modelled as the phase of a synthesis
filter excited by an impulse. In many Codec 2 modes the synthesis
filter is a LPC filter. Unlike the first order model the position
of the impulse is not transmitted, so we create an excitation pulse
train using a rule based approach.
Consider a pulse train with a pulse starting time n=0, with pulses
repeated at a rate of Wo, the fundamental frequency. A pulse train
in the time domain is equivalent to harmonics in the frequency
domain. We can make an excitation pulse train using a sum of
sinsusoids:
for(m=1; m<=L; m++)
ex[n] = cos(m*Wo*n)
Note: the Octave script ../octave/phase.m is an example of this if
you would like to try making a pulse train.
The phase of each excitation harmonic is:
arg(E[m]) = mWo
where E[m] are the complex excitation (freq domain) samples,
arg(x), just returns the phase of a complex sample x.
As we don't transmit the pulse position for this model, we need to
synthesise it. Now the excitation pulses occur at a rate of Wo.
This means the phase of the first harmonic advances by N_SAMP samples
over a synthesis frame of N_SAMP samples. For example if Wo is pi/20
(200 Hz), then over a 10ms frame (N_SAMP=80 samples), the phase of the
first harmonic would advance (pi/20)*80 = 4*pi or two complete
cycles.
We generate the excitation phase of the fundamental (first
harmonic):
arg[E[1]] = Wo*N_SAMP;
We then relate the phase of the m-th excitation harmonic to the
phase of the fundamental as:
arg(E[m]) = m*arg(E[1])
This E[m] then gets passed through the LPC synthesis filter to
determine the final harmonic phase.
Comparing to speech synthesised using original phases:
- Through headphones speech synthesised with this model is not as
good. Through a loudspeaker it is very close to original phases.
- If there are voicing errors, the speech can sound clicky or
staticy. If V speech is mistakenly declared UV, this model tends to
synthesise impulses or clicks, as there is usually very little shift or
dispersion through the LPC synthesis filter.
- When combined with LPC amplitude modelling there is an additional
drop in quality. I am not sure why, theory is interformant energy
is raised making any phase errors more obvious.
NOTES:
1/ This synthesis model is effectively the same as a simple LPC-10
vocoders, and yet sounds much better. Why? Conventional wisdom
(AMBE, MELP) says mixed voicing is required for high quality
speech.
2/ I am pretty sure the Lincoln Lab sinusoidal coding guys (like xMBE
also from MIT) first described this zero phase model, I need to look
up the paper.
3/ Note that this approach could cause some discontinuities in
the phase at the edge of synthesis frames, as no attempt is made
to make sure that the phase tracks are continuous (the excitation
phases are continuous, but not the final phases after filtering
by the LPC spectra). Technically this is a bad thing. However
this may actually be a good thing, disturbing the phase tracks a
bit. More research needed, e.g. test a synthesis model that adds
a small delta-W to make phase tracks line up for voiced
harmonics.
\*---------------------------------------------------------------------------*/
void phase_synth_zero_order(
int n_samp,
MODEL *model,
float *ex_phase, /* excitation phase of fundamental */
COMP H[] /* L synthesis filter freq domain samples */
)
{
int m;
float new_phi;
COMP Ex[MAX_AMP+1]; /* excitation samples */
COMP A_[MAX_AMP+1]; /* synthesised harmonic samples */
/*
Update excitation fundamental phase track, this sets the position
of each pitch pulse during voiced speech. After much experiment
I found that using just this frame's Wo improved quality for UV
sounds compared to interpolating two frames Wo like this:
ex_phase[0] += (*prev_Wo+model->Wo)*N_SAMP/2;
*/
ex_phase[0] += (model->Wo)*n_samp;
ex_phase[0] -= TWO_PI*floorf(ex_phase[0]/TWO_PI + 0.5);
for(m=1; m<=model->L; m++) {
/* generate excitation */
if (model->voiced) {
Ex[m].real = cosf(ex_phase[0]*m);
Ex[m].imag = sinf(ex_phase[0]*m);
}
else {
/* When a few samples were tested I found that LPC filter
phase is not needed in the unvoiced case, but no harm in
keeping it.
*/
float phi = TWO_PI*(float)codec2_rand()/CODEC2_RAND_MAX;
Ex[m].real = cosf(phi);
Ex[m].imag = sinf(phi);
}
/* filter using LPC filter */
A_[m].real = H[m].real*Ex[m].real - H[m].imag*Ex[m].imag;
A_[m].imag = H[m].imag*Ex[m].real + H[m].real*Ex[m].imag;
/* modify sinusoidal phase */
new_phi = atan2f(A_[m].imag, A_[m].real+1E-12);
model->phi[m] = new_phi;
}
}
/*---------------------------------------------------------------------------*\
FUNCTION....: mag_to_phase
AUTHOR......: David Rowe
DATE CREATED: Jan 2017
Algorithm for http://www.dsprelated.com/showcode/20.php ported to C. See
also Octave function mag_to_phase.m
Given a magnitude spectrum in dB, returns a minimum-phase phase
spectra.
\*---------------------------------------------------------------------------*/
void mag_to_phase(float phase[], /* Nfft/2+1 output phase samples in radians */
float Gdbfk[], /* Nfft/2+1 postive freq amplitudes samples in dB */
int Nfft,
codec2_fft_cfg fft_fwd_cfg,
codec2_fft_cfg fft_inv_cfg
)
{
COMP Sdb[Nfft], c[Nfft], cf[Nfft], Cf[Nfft];
int Ns = Nfft/2+1;
int i;
/* install negative frequency components, 1/Nfft takes into
account kiss fft lack of scaling on ifft */
Sdb[0].real = Gdbfk[0];
Sdb[0].imag = 0.0;
for(i=1; i<Ns; i++) {
Sdb[i].real = Sdb[Nfft-i].real = Gdbfk[i];
Sdb[i].imag = Sdb[Nfft-i].imag = 0.0;
}
/* compute real cepstrum from log magnitude spectrum */
codec2_fft(fft_inv_cfg, Sdb, c);
for(i=0; i<Nfft; i++) {
c[i].real /= (float)Nfft;
c[i].imag /= (float)Nfft;
}
/* Fold cepstrum to reflect non-min-phase zeros inside unit circle */
cf[0] = c[0];
for(i=1; i<Ns-1; i++) {
cf[i] = cadd(c[i],c[Nfft-i]);
}
cf[Ns-1] = c[Ns-1];
for(i=Ns; i<Nfft; i++) {
cf[i].real = 0.0;
cf[i].imag = 0.0;
}
/* Cf = dB_magnitude + j * minimum_phase */
codec2_fft(fft_fwd_cfg, cf, Cf);
/* The maths says we are meant to be using log(x), not 20*log10(x),
so we need to scale the phase to account for this:
log(x) = 20*log10(x)/scale */
float scale = (20.0/logf(10.0));
for(i=0; i<Ns; i++) {
phase[i] = Cf[i].imag/scale;
}
}
+39
View File
@@ -0,0 +1,39 @@
/*---------------------------------------------------------------------------*\
FILE........: phase.h
AUTHOR......: David Rowe
DATE CREATED: 1/2/09
Functions for modelling phase.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __PHASE__
#define __PHASE__
#include "codec2_fft.h"
#include "comp.h"
void sample_phase(MODEL *model, COMP filter_phase[], COMP A[]);
void phase_synth_zero_order(int n_samp, MODEL *model, float *ex_phase, COMP filter_phase[]);
void mag_to_phase(float phase[], float Gdbfk[], int Nfft, codec2_fft_cfg fwd_cfg, codec2_fft_cfg inv_cfg);
#endif
+39
View File
@@ -0,0 +1,39 @@
/*---------------------------------------------------------------------------*\
FILE........: phaseexp.h
AUTHOR......: David Rowe
DATE CREATED: June 2012
Experimental functions for quantising, modelling and synthesising phase.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2012 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __PHASEEXP__
#define __PHASEEXP__
#include "kiss_fft.h"
struct PEXP;
struct PEXP * phase_experiment_create();
void phase_experiment_destroy(struct PEXP *pexp);
void phase_experiment(struct PEXP *pexp, MODEL *model, char *arg);
#endif
+41
View File
@@ -0,0 +1,41 @@
/* Generated by pilot_coeff_file() Octave function */
// const removed since this provides gain
// on the STM32F4 platform
#ifdef CORTEX_M4
/* const */ float pilot_coeff[]={
#else
const float pilot_coeff[]={
#endif
0.00223001,
0.00301037,
0.00471258,
0.0075934,
0.0118145,
0.0174153,
0.0242969,
0.0322204,
0.0408199,
0.0496286,
0.0581172,
0.0657392,
0.0719806,
0.0764066,
0.0787022,
0.0787022,
0.0764066,
0.0719806,
0.0657392,
0.0581172,
0.0496286,
0.0408199,
0.0322204,
0.0242969,
0.0174153,
0.0118145,
0.0075934,
0.00471258,
0.00301037,
0.00223001
};
+6
View File
@@ -0,0 +1,6 @@
/* Generated by write_pilot_file() Octave function */
float pilots_coh[][PILOTS_NC]={
{ 1.000000, -1.000000, 1.000000, -1.000000, 1.000000, -1.000000, -1.000000},
{ -1.000000, 1.000000, 1.000000, -1.000000, 1.000000, 1.000000, 1.000000}
};
+142
View File
@@ -0,0 +1,142 @@
/*---------------------------------------------------------------------------*\
FILE........: postfilter.c
AUTHOR......: David Rowe
DATE CREATED: 13/09/09
Postfilter to improve sound quality for speech with high levels of
background noise. Unlike mixed-excitation models requires no bits
to be transmitted to handle background noise.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "defines.h"
#include "comp.h"
#include "dump.h"
#include "sine.h"
#include "postfilter.h"
/*---------------------------------------------------------------------------*\
DEFINES
\*---------------------------------------------------------------------------*/
#define BG_THRESH 40.0 /* only consider low levels signals for bg_est */
#define BG_BETA 0.1 /* averaging filter constant */
#define BG_MARGIN 6.0 /* harmonics this far above BG noise are
randomised. Helped make bg noise less
spikey (impulsive) for mmt1, but speech was
perhaps a little rougher.
*/
/*---------------------------------------------------------------------------*\
postfilter()
The post filter is designed to help with speech corrupted by
background noise. The zero phase model tends to make speech with
background noise sound "clicky". With high levels of background
noise the low level inter-formant parts of the spectrum will contain
noise rather than speech harmonics, so modelling them as voiced
(i.e. a continuous, non-random phase track) is inaccurate.
Some codecs (like MBE) have a mixed voicing model that breaks the
spectrum into voiced and unvoiced regions. Several bits/frame
(5-12) are required to transmit the frequency selective voicing
information. Mixed excitation also requires accurate voicing
estimation (parameter estimators always break occasionally under
exceptional conditions).
In our case we use a post filter approach which requires no
additional bits to be transmitted. The decoder measures the average
level of the background noise during unvoiced frames. If a harmonic
is less than this level it is made unvoiced by randomising it's
phases.
This idea is rather experimental. Some potential problems that may
happen:
1/ If someone says "aaaaaaaahhhhhhhhh" will background estimator track
up to speech level? This would be a bad thing.
2/ If background noise suddenly dissapears from the source speech does
estimate drop quickly? What is noise suddenly re-appears?
3/ Background noise with a non-flat sepctrum. Current algorithm just
comsiders scpetrum as a whole, but this could be broken up into
bands, each with their own estimator.
4/ Males and females with the same level of background noise. Check
performance the same. Changing Wo affects width of each band, may
affect bg energy estimates.
5/ Not sure what happens during long periods of voiced speech
e.g. "sshhhhhhh"
\*---------------------------------------------------------------------------*/
void postfilter(
MODEL *model,
float *bg_est
)
{
int m, uv;
float e, thresh;
/* determine average energy across spectrum */
e = 1E-12;
for(m=1; m<=model->L; m++)
e += model->A[m]*model->A[m];
assert(e > 0.0);
e = 10.0*log10f(e/model->L);
/* If beneath threhold, update bg estimate. The idea
of the threshold is to prevent updating during high level
speech. */
if ((e < BG_THRESH) && !model->voiced)
*bg_est = *bg_est*(1.0 - BG_BETA) + e*BG_BETA;
/* now mess with phases during voiced frames to make any harmonics
less then our background estimate unvoiced.
*/
uv = 0;
thresh = powf(10.0, (*bg_est + BG_MARGIN)/20.0);
if (model->voiced)
for(m=1; m<=model->L; m++)
if (model->A[m] < thresh) {
model->phi[m] = TWO_PI*(float)codec2_rand()/CODEC2_RAND_MAX;
uv++;
}
#ifdef DUMP
dump_bg(e, *bg_est, 100.0*uv/model->L);
#endif
}
+33
View File
@@ -0,0 +1,33 @@
/*---------------------------------------------------------------------------*\
FILE........: postfilter.h
AUTHOR......: David Rowe
DATE CREATED: 13/09/09
Postfilter header file.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __POSTFILTER__
#define __POSTFILTER__
void postfilter(MODEL *model, float *bg_est);
#endif
File diff suppressed because it is too large Load Diff
+141
View File
@@ -0,0 +1,141 @@
/*---------------------------------------------------------------------------*\
FILE........: quantise.h
AUTHOR......: David Rowe
DATE CREATED: 31/5/92
Quantisation functions for the sinusoidal coder.
\*---------------------------------------------------------------------------*/
/*
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __QUANTISE__
#define __QUANTISE__
#include "codec2_fft.h"
#include "comp.h"
#define WO_BITS 7
#define WO_LEVELS (1<<WO_BITS)
#define WO_DT_BITS 3
#define E_BITS 5
#define E_LEVELS (1<<E_BITS)
#define E_MIN_DB -10.0
#define E_MAX_DB 40.0
#define LSP_SCALAR_INDEXES 10
#define LSPD_SCALAR_INDEXES 10
#define LSP_PRED_VQ_INDEXES 3
#define LSP_DIFF_FREQ_INDEXES 5
#define LSP_DIFF_TIME_BITS 7
#define LSPDT_ALL 0
#define LSPDT_LOW 1
#define LSPDT_HIGH 2
#define WO_E_BITS 8
#define LPCPF_GAMMA 0.5
#define LPCPF_BETA 0.2
void quantise_init();
float lpc_model_amplitudes(float Sn[], float w[], MODEL *model, int order,
int lsp,float ak[]);
void aks_to_M2(codec2_fftr_cfg fftr_fwd_cfg, float ak[], int order, MODEL *model,
float E, float *snr, int dump, int sim_pf,
int pf, int bass_boost, float beta, float gamma, COMP Aw[]);
int encode_Wo(C2CONST *c2const, float Wo, int bits);
float decode_Wo(C2CONST *c2const, int index, int bits);
int encode_log_Wo(C2CONST *c2const, float Wo, int bits);
float decode_log_Wo(C2CONST *c2const, int index, int bits);
#if 0
int encode_Wo_dt(C2CONST *c2const, float Wo, float prev_Wo);
float decode_Wo_dt(C2CONST *c2const, int index, float prev_Wo);
#endif
void encode_lsps_scalar(int indexes[], float lsp[], int order);
void decode_lsps_scalar(float lsp[], int indexes[], int order);
void encode_lspds_scalar(int indexes[], float lsp[], int order);
void decode_lspds_scalar(float lsp[], int indexes[], int order);
void encode_lsps_diff_freq_vq(int indexes[], float lsp[], int order);
void decode_lsps_diff_freq_vq(float lsp_[], int indexes[], int order);
void encode_lsps_diff_time(int indexes[],
float lsp[],
float lsp__prev[],
int order);
void decode_lsps_diff_time(float lsp_[],
int indexes[],
float lsp__prev[],
int order);
void encode_lsps_vq(int *indexes, float *x, float *xq, int order);
void decode_lsps_vq(int *indexes, float *xq, int order, int stages);
long quantise(const float * cb, float vec[], float w[], int k, int m, float *se);
void lspvq_quantise(float lsp[], float lsp_[], int order);
void lspjnd_quantise(float lsp[], float lsp_[], int order);
void lspdt_quantise(float lsps[], float lsps_[], float lsps__prev[], int mode);
void lspjvm_quantise(float lsps[], float lsps_[], int order);
void lspanssi_quantise(float lsps[], float lsps_[], int order, int mbest_entries);
float lspmelvq_quantise(float *x, float *xq, int order);
float lspmelvq_mbest_encode(int *indexes, float *x, float *xq, int ndim, int mbest_entries);
void lspmelvq_decode(int *indexes, float *xq, int ndim);
void encode_mels_scalar(int mel_indexes[], float mels[], int order);
void decode_mels_scalar(float mels[], int mel_indexes[], int order);
void quantise_WoE(C2CONST *c2const, MODEL *model, float *e, float xq[]);
int encode_WoE(MODEL *model, float e, float xq[]);
void decode_WoE(C2CONST *c2const, MODEL *model, float *e, float xq[], int n1);
int encode_energy(float e, int bits);
float decode_energy(int index, int bits);
void pack(unsigned char * bits, unsigned int *nbit, int index, unsigned int index_bits);
void pack_natural_or_gray(unsigned char * bits, unsigned int *nbit, int index, unsigned int index_bits, unsigned int gray);
int unpack(const unsigned char * bits, unsigned int *nbit, unsigned int index_bits);
int unpack_natural_or_gray(const unsigned char * bits, unsigned int *nbit, unsigned int index_bits, unsigned int gray);
int lsp_bits(int i);
int lspd_bits(int i);
int lspdt_bits(int i);
int lsp_pred_vq_bits(int i);
int mel_bits(int i);
int lspmelvq_cb_bits(int i);
void apply_lpc_correction(MODEL *model);
float speech_to_uq_lsps(float lsp[],
float ak[],
float Sn[],
float w[],
int m_pitch,
int order
);
int check_lsp_order(float lsp[], int lpc_order);
void bw_expand_lsps(float lsp[], int order, float min_sep_low, float min_sep_high);
void bw_expand_lsps2(float lsp[], int order);
void locate_lsps_jnd_steps(float lsp[], int order);
float decode_amplitudes(MODEL *model,
float ak[],
int lsp_indexes[],
int energy_index,
float lsps[],
float *e);
#endif
+964
View File
@@ -0,0 +1,964 @@
/* Generated by rn_file() Octave function */
const float gt_alpha5_root[]={
2.86997e-05,
2.2286e-05,
1.82863e-05,
1.42303e-05,
1.04905e-05,
6.70859e-06,
3.05918e-06,
-6.22187e-07,
-4.22748e-06,
-7.85603e-06,
-1.14317e-05,
-1.50227e-05,
-1.85712e-05,
-2.21275e-05,
-2.56455e-05,
-2.91642e-05,
-3.26453e-05,
-3.61199e-05,
-3.95556e-05,
-4.29778e-05,
-4.63581e-05,
-4.97179e-05,
-5.3032e-05,
-5.63184e-05,
-5.95548e-05,
-6.27565e-05,
-6.59032e-05,
-6.90085e-05,
-7.20538e-05,
-7.50509e-05,
-7.7983e-05,
-8.08605e-05,
-8.36678e-05,
-8.64141e-05,
-8.9085e-05,
-9.16888e-05,
-9.42119e-05,
-9.66619e-05,
-9.9026e-05,
-0.000101311,
-0.000103505,
-0.000105614,
-0.000107627,
-0.00010955,
-0.000111372,
-0.000113099,
-0.00011472,
-0.000116241,
-0.000117652,
-0.000118959,
-0.000120152,
-0.000121235,
-0.000122201,
-0.000123053,
-0.000123784,
-0.000124397,
-0.000124884,
-0.00012525,
-0.000125487,
-0.000125598,
-0.000125578,
-0.000125428,
-0.000125145,
-0.000124729,
-0.000124185,
-0.000123518,
-0.000122709,
-0.000121766,
-0.000120685,
-0.000119471,
-0.000118119,
-0.000116633,
-0.000115009,
-0.000113251,
-0.000111356,
-0.000109326,
-0.00010716,
-0.00010486,
-0.000102424,
-9.98553e-05,
-9.71528e-05,
-9.43199e-05,
-9.13551e-05,
-8.82623e-05,
-8.50404e-05,
-8.16936e-05,
-7.82211e-05,
-7.46271e-05,
-7.09109e-05,
-6.70773e-05,
-6.31256e-05,
-5.90607e-05,
-5.48823e-05,
-5.05954e-05,
-4.62001e-05,
-4.17016e-05,
-3.71002e-05,
-3.24015e-05,
-2.7606e-05,
-2.27195e-05,
-1.77428e-05,
-1.2682e-05,
-7.53795e-06,
-2.31702e-06,
2.97965e-06,
8.34567e-06,
1.37796e-05,
1.9275e-05,
2.483e-05,
3.04382e-05,
3.60975e-05,
4.18011e-05,
4.75467e-05,
5.33273e-05,
5.91403e-05,
6.49787e-05,
7.08393e-05,
7.67152e-05,
8.26029e-05,
8.84957e-05,
9.43895e-05,
0.000100278,
0.000106157,
0.00011202,
0.000117864,
0.000123681,
0.000129468,
0.000135218,
0.000140929,
0.000146583,
0.000152183,
0.000157725,
0.000163202,
0.000168608,
0.000173938,
0.000179183,
0.00018434,
0.0001894,
0.00019436,
0.000199211,
0.000203949,
0.000208568,
0.000213063,
0.000217426,
0.000221654,
0.00022574,
0.000229678,
0.000233463,
0.000237089,
0.000240551,
0.000243843,
0.000246959,
0.000249895,
0.000252644,
0.000255202,
0.000257562,
0.000259721,
0.000261672,
0.000263411,
0.000264933,
0.000266234,
0.000267308,
0.000268152,
0.00026876,
0.000269128,
0.000269253,
0.000269129,
0.000268754,
0.000268123,
0.000267232,
0.000266079,
0.000264658,
0.000262968,
0.000261006,
0.000258767,
0.000256251,
0.000253453,
0.000250373,
0.000247007,
0.000243354,
0.000239412,
0.00023518,
0.000230655,
0.000225837,
0.000220723,
0.000215314,
0.000209608,
0.000203605,
0.000197304,
0.000190706,
0.000183812,
0.000176621,
0.000169145,
0.000161363,
0.000153275,
0.000144895,
0.000136224,
0.000127266,
0.00011802,
0.000108491,
9.8679e-05,
8.85877e-05,
7.82196e-05,
6.7577e-05,
5.66636e-05,
4.54822e-05,
3.40369e-05,
2.23311e-05,
1.03695e-05,
-1.844e-06,
-1.43041e-05,
-2.70061e-05,
-3.99444e-05,
-5.31139e-05,
-6.65082e-05,
-8.01218e-05,
-9.39481e-05,
-0.000107981,
-0.000122213,
-0.000136638,
-0.000151248,
-0.000166036,
-0.000180995,
-0.000196115,
-0.00021139,
-0.000226811,
-0.000242369,
-0.000258056,
-0.000273861,
-0.000289776,
-0.000305792,
-0.000321898,
-0.000338084,
-0.000354342,
-0.00037066,
-0.000387027,
-0.000403434,
-0.00041987,
-0.000436324,
-0.000452784,
-0.00046924,
-0.00048568,
-0.000502091,
-0.000518464,
-0.000534785,
-0.000551043,
-0.000567225,
-0.000583319,
-0.000599314,
-0.000615196,
-0.000630955,
-0.000646575,
-0.000662049,
-0.000677361,
-0.000692506,
-0.000707464,
-0.00072229,
-0.000736922,
-0.000751266,
-0.000765372,
-0.000779217,
-0.000792798,
-0.000806094,
-0.000819098,
-0.000831793,
-0.000844168,
-0.000856207,
-0.000867898,
-0.000879227,
-0.00089018,
-0.000900744,
-0.000910906,
-0.000920652,
-0.00092997,
-0.000938844,
-0.000947263,
-0.000955214,
-0.000962682,
-0.000969654,
-0.000976119,
-0.000982062,
-0.00098747,
-0.000992332,
-0.000996634,
-0.00100036,
-0.00100351,
-0.00100606,
-0.001008,
-0.00100932,
-0.00101,
-0.00101005,
-0.00100943,
-0.00100816,
-0.0010062,
-0.00100356,
-0.00100021,
-0.000996162,
-0.000991392,
-0.000985892,
-0.000979654,
-0.000972668,
-0.000964925,
-0.000956415,
-0.000947131,
-0.000937065,
-0.000926208,
-0.000914552,
-0.00090209,
-0.000888816,
-0.000874721,
-0.0008598,
-0.000844046,
-0.000827453,
-0.000810015,
-0.000791726,
-0.000772581,
-0.000752576,
-0.000731704,
-0.000709965,
-0.00068735,
-0.000663865,
-0.000639509,
-0.000614269,
-0.000588146,
-0.000561139,
-0.000533246,
-0.000504468,
-0.000474802,
-0.000444251,
-0.000412813,
-0.00038049,
-0.000347281,
-0.000313189,
-0.000278215,
-0.000242361,
-0.000205629,
-0.000168024,
-0.000129546,
-9.02024e-05,
-4.99954e-05,
-8.93026e-06,
3.2988e-05,
7.57537e-05,
0.000119361,
0.000163804,
0.000209075,
0.000255167,
0.000302074,
0.000349786,
0.000398297,
0.000447596,
0.000497676,
0.000548526,
0.000600136,
0.000652497,
0.000705598,
0.000759427,
0.000813972,
0.000869223,
0.000925166,
0.000981789,
0.00103908,
0.00109702,
0.00115561,
0.00121482,
0.00127464,
0.00133505,
0.00139605,
0.00145762,
0.00151973,
0.00158238,
0.00164555,
0.00170922,
0.00177337,
0.00183799,
0.00190305,
0.00196854,
0.00203445,
0.00210075,
0.00216742,
0.00223445,
0.00230181,
0.00236949,
0.00243747,
0.00250572,
0.00257423,
0.00264296,
0.00271192,
0.00278107,
0.00285039,
0.00291986,
0.00298947,
0.00305918,
0.00312898,
0.00319884,
0.00326874,
0.00333866,
0.00340857,
0.00347846,
0.00354831,
0.00361808,
0.00368775,
0.00375731,
0.00382673,
0.00389599,
0.00396506,
0.00403393,
0.00410256,
0.00417094,
0.00423904,
0.00430684,
0.00437431,
0.00444144,
0.0045082,
0.00457457,
0.00464052,
0.00470603,
0.00477108,
0.00483565,
0.00489972,
0.00496325,
0.00502623,
0.00508865,
0.00515046,
0.00521166,
0.00527223,
0.00533213,
0.00539135,
0.00544987,
0.00550766,
0.00556472,
0.005621,
0.00567651,
0.00573121,
0.00578508,
0.00583811,
0.00589028,
0.00594157,
0.00599196,
0.00604143,
0.00608996,
0.00613754,
0.00618415,
0.00622977,
0.00627439,
0.00631798,
0.00636054,
0.00640204,
0.0064425,
0.00648186,
0.00652009,
0.00655722,
0.00659322,
0.00662808,
0.00666179,
0.00669433,
0.00672571,
0.00675589,
0.00678488,
0.00681266,
0.00683921,
0.00686454,
0.00688863,
0.00691147,
0.00693305,
0.00695336,
0.0069724,
0.00699016,
0.00700663,
0.00702181,
0.00703569,
0.00704826,
0.00705952,
0.00706947,
0.00707809,
0.0070854,
0.00709138,
0.00709604,
0.00709937,
0.00710136,
0.00710203,
0.00710136,
0.00709937,
0.00709604,
0.00709138,
0.0070854,
0.00707809,
0.00706947,
0.00705952,
0.00704826,
0.00703569,
0.00702181,
0.00700663,
0.00699016,
0.0069724,
0.00695336,
0.00693305,
0.00691147,
0.00688863,
0.00686454,
0.00683921,
0.00681266,
0.00678488,
0.00675589,
0.00672571,
0.00669433,
0.00666179,
0.00662808,
0.00659322,
0.00655722,
0.00652009,
0.00648186,
0.0064425,
0.00640204,
0.00636054,
0.00631798,
0.00627439,
0.00622977,
0.00618415,
0.00613754,
0.00608996,
0.00604143,
0.00599196,
0.00594157,
0.00589028,
0.00583811,
0.00578508,
0.00573121,
0.00567651,
0.005621,
0.00556472,
0.00550766,
0.00544987,
0.00539135,
0.00533213,
0.00527223,
0.00521166,
0.00515046,
0.00508865,
0.00502623,
0.00496325,
0.00489972,
0.00483565,
0.00477108,
0.00470603,
0.00464052,
0.00457457,
0.0045082,
0.00444144,
0.00437431,
0.00430684,
0.00423904,
0.00417094,
0.00410256,
0.00403393,
0.00396506,
0.00389599,
0.00382673,
0.00375731,
0.00368775,
0.00361808,
0.00354831,
0.00347846,
0.00340857,
0.00333866,
0.00326874,
0.00319884,
0.00312898,
0.00305918,
0.00298947,
0.00291986,
0.00285039,
0.00278107,
0.00271192,
0.00264296,
0.00257423,
0.00250572,
0.00243747,
0.00236949,
0.00230181,
0.00223445,
0.00216742,
0.00210075,
0.00203445,
0.00196854,
0.00190305,
0.00183799,
0.00177337,
0.00170922,
0.00164555,
0.00158238,
0.00151973,
0.00145762,
0.00139605,
0.00133505,
0.00127464,
0.00121482,
0.00115561,
0.00109702,
0.00103908,
0.000981789,
0.000925166,
0.000869223,
0.000813972,
0.000759427,
0.000705598,
0.000652497,
0.000600136,
0.000548526,
0.000497676,
0.000447596,
0.000398297,
0.000349786,
0.000302074,
0.000255167,
0.000209075,
0.000163804,
0.000119361,
7.57537e-05,
3.2988e-05,
-8.93026e-06,
-4.99954e-05,
-9.02024e-05,
-0.000129546,
-0.000168024,
-0.000205629,
-0.000242361,
-0.000278215,
-0.000313189,
-0.000347281,
-0.00038049,
-0.000412813,
-0.000444251,
-0.000474802,
-0.000504468,
-0.000533246,
-0.000561139,
-0.000588146,
-0.000614269,
-0.000639509,
-0.000663865,
-0.00068735,
-0.000709965,
-0.000731704,
-0.000752576,
-0.000772581,
-0.000791726,
-0.000810015,
-0.000827453,
-0.000844046,
-0.0008598,
-0.000874721,
-0.000888816,
-0.00090209,
-0.000914552,
-0.000926208,
-0.000937065,
-0.000947131,
-0.000956415,
-0.000964925,
-0.000972668,
-0.000979654,
-0.000985892,
-0.000991392,
-0.000996162,
-0.00100021,
-0.00100356,
-0.0010062,
-0.00100816,
-0.00100943,
-0.00101005,
-0.00101,
-0.00100932,
-0.001008,
-0.00100606,
-0.00100351,
-0.00100036,
-0.000996634,
-0.000992332,
-0.00098747,
-0.000982062,
-0.000976119,
-0.000969654,
-0.000962682,
-0.000955214,
-0.000947263,
-0.000938844,
-0.00092997,
-0.000920652,
-0.000910906,
-0.000900744,
-0.00089018,
-0.000879227,
-0.000867898,
-0.000856207,
-0.000844168,
-0.000831793,
-0.000819098,
-0.000806094,
-0.000792798,
-0.000779217,
-0.000765372,
-0.000751266,
-0.000736922,
-0.00072229,
-0.000707464,
-0.000692506,
-0.000677361,
-0.000662049,
-0.000646575,
-0.000630955,
-0.000615196,
-0.000599314,
-0.000583319,
-0.000567225,
-0.000551043,
-0.000534785,
-0.000518464,
-0.000502091,
-0.00048568,
-0.00046924,
-0.000452784,
-0.000436324,
-0.00041987,
-0.000403434,
-0.000387027,
-0.00037066,
-0.000354342,
-0.000338084,
-0.000321898,
-0.000305792,
-0.000289776,
-0.000273861,
-0.000258056,
-0.000242369,
-0.000226811,
-0.00021139,
-0.000196115,
-0.000180995,
-0.000166036,
-0.000151248,
-0.000136638,
-0.000122213,
-0.000107981,
-9.39481e-05,
-8.01218e-05,
-6.65082e-05,
-5.31139e-05,
-3.99444e-05,
-2.70061e-05,
-1.43041e-05,
-1.844e-06,
1.03695e-05,
2.23311e-05,
3.40369e-05,
4.54822e-05,
5.66636e-05,
6.7577e-05,
7.82196e-05,
8.85877e-05,
9.8679e-05,
0.000108491,
0.00011802,
0.000127266,
0.000136224,
0.000144895,
0.000153275,
0.000161363,
0.000169145,
0.000176621,
0.000183812,
0.000190706,
0.000197304,
0.000203605,
0.000209608,
0.000215314,
0.000220723,
0.000225837,
0.000230655,
0.00023518,
0.000239412,
0.000243354,
0.000247007,
0.000250373,
0.000253453,
0.000256251,
0.000258767,
0.000261006,
0.000262968,
0.000264658,
0.000266079,
0.000267232,
0.000268123,
0.000268754,
0.000269129,
0.000269253,
0.000269128,
0.00026876,
0.000268152,
0.000267308,
0.000266234,
0.000264933,
0.000263411,
0.000261672,
0.000259721,
0.000257562,
0.000255202,
0.000252644,
0.000249895,
0.000246959,
0.000243843,
0.000240551,
0.000237089,
0.000233463,
0.000229678,
0.00022574,
0.000221654,
0.000217426,
0.000213063,
0.000208568,
0.000203949,
0.000199211,
0.00019436,
0.0001894,
0.00018434,
0.000179183,
0.000173938,
0.000168608,
0.000163202,
0.000157725,
0.000152183,
0.000146583,
0.000140929,
0.000135218,
0.000129468,
0.000123681,
0.000117864,
0.00011202,
0.000106157,
0.000100278,
9.43895e-05,
8.84957e-05,
8.26029e-05,
7.67152e-05,
7.08393e-05,
6.49787e-05,
5.91403e-05,
5.33273e-05,
4.75467e-05,
4.18011e-05,
3.60975e-05,
3.04382e-05,
2.483e-05,
1.9275e-05,
1.37796e-05,
8.34567e-06,
2.97965e-06,
-2.31702e-06,
-7.53795e-06,
-1.2682e-05,
-1.77428e-05,
-2.27195e-05,
-2.7606e-05,
-3.24015e-05,
-3.71002e-05,
-4.17016e-05,
-4.62001e-05,
-5.05954e-05,
-5.48823e-05,
-5.90607e-05,
-6.31256e-05,
-6.70773e-05,
-7.09109e-05,
-7.46271e-05,
-7.82211e-05,
-8.16936e-05,
-8.50404e-05,
-8.82623e-05,
-9.13551e-05,
-9.43199e-05,
-9.71528e-05,
-9.98553e-05,
-0.000102424,
-0.00010486,
-0.00010716,
-0.000109326,
-0.000111356,
-0.000113251,
-0.000115009,
-0.000116633,
-0.000118119,
-0.000119471,
-0.000120685,
-0.000121766,
-0.000122709,
-0.000123518,
-0.000124185,
-0.000124729,
-0.000125145,
-0.000125428,
-0.000125578,
-0.000125598,
-0.000125487,
-0.00012525,
-0.000124884,
-0.000124397,
-0.000123784,
-0.000123053,
-0.000122201,
-0.000121235,
-0.000120152,
-0.000118959,
-0.000117652,
-0.000116241,
-0.00011472,
-0.000113099,
-0.000111372,
-0.00010955,
-0.000107627,
-0.000105614,
-0.000103505,
-0.000101311,
-9.9026e-05,
-9.66619e-05,
-9.42119e-05,
-9.16888e-05,
-8.9085e-05,
-8.64141e-05,
-8.36678e-05,
-8.08605e-05,
-7.7983e-05,
-7.50509e-05,
-7.20538e-05,
-6.90085e-05,
-6.59032e-05,
-6.27565e-05,
-5.95548e-05,
-5.63184e-05,
-5.3032e-05,
-4.97179e-05,
-4.63581e-05,
-4.29778e-05,
-3.95556e-05,
-3.61199e-05,
-3.26453e-05,
-2.91642e-05,
-2.56455e-05,
-2.21275e-05,
-1.85712e-05,
-1.50227e-05,
-1.14317e-05,
-7.85603e-06,
-4.22748e-06,
-6.22187e-07,
3.05918e-06,
6.70859e-06,
1.04905e-05,
1.42303e-05,
1.82863e-05,
2.2286e-05
};
+604
View File
@@ -0,0 +1,604 @@
/* Generated by rn_file() Octave function */
const float gt_alpha5_root_coh[]={
4.05576e-05,
2.58255e-05,
1.58964e-05,
5.78773e-06,
-3.71244e-06,
-1.33229e-05,
-2.2664e-05,
-3.20611e-05,
-4.12734e-05,
-5.04935e-05,
-5.9545e-05,
-6.85565e-05,
-7.73902e-05,
-8.6137e-05,
-9.46835e-05,
-0.000103097,
-0.000111281,
-0.000119289,
-0.000127034,
-0.000134559,
-0.000141789,
-0.000148756,
-0.000155393,
-0.000161723,
-0.000167689,
-0.000173315,
-0.00017854,
-0.000183382,
-0.000187794,
-0.000191793,
-0.000195333,
-0.000198429,
-0.000201038,
-0.000203173,
-0.000204797,
-0.000205922,
-0.000206515,
-0.00020659,
-0.000206117,
-0.000205109,
-0.000203541,
-0.000201427,
-0.000198743,
-0.000195505,
-0.000191693,
-0.000187324,
-0.000182382,
-0.000176885,
-0.000170822,
-0.00016421,
-0.000157041,
-0.000149335,
-0.000141089,
-0.000132323,
-0.000123038,
-0.000113258,
-0.000102985,
-9.22439e-05,
-8.10442e-05,
-6.94109e-05,
-5.73536e-05,
-4.49012e-05,
-3.20661e-05,
-1.88794e-05,
-5.35615e-06,
8.47105e-06,
2.25833e-05,
3.69472e-05,
5.15418e-05,
6.63317e-05,
8.12934e-05,
9.63895e-05,
0.000111594,
0.000126869,
0.000142183,
0.000157497,
0.000172781,
0.000187996,
0.000203111,
0.000218088,
0.000232892,
0.000247474,
0.000261806,
0.000275847,
0.000289559,
0.000302903,
0.000315839,
0.00032833,
0.000340339,
0.000351824,
0.000362751,
0.00037308,
0.000382774,
0.000391795,
0.000400108,
0.000407675,
0.000414464,
0.000420437,
0.000425565,
0.000429812,
0.000433151,
0.000435544,
0.000436975,
0.000437401,
0.000436865,
0.000435237,
0.00043246,
0.000428592,
0.000423608,
0.000417497,
0.00041024,
0.000401823,
0.000392231,
0.000381449,
0.000369471,
0.000356284,
0.000341885,
0.000326267,
0.00030943,
0.000291373,
0.000272099,
0.000251612,
0.000229921,
0.000207034,
0.000182964,
0.000157726,
0.000131338,
0.000103821,
7.51956e-05,
4.54842e-05,
1.4721e-05,
-1.7067e-05,
-4.98479e-05,
-8.35883e-05,
-0.000118248,
-0.00015379,
-0.000190167,
-0.000227336,
-0.000265248,
-0.000303856,
-0.000343104,
-0.000382942,
-0.00042331,
-0.000464152,
-0.000505403,
-0.000547003,
-0.000588883,
-0.000630979,
-0.000673218,
-0.000715533,
-0.000757849,
-0.000800092,
-0.000842187,
-0.000884054,
-0.000925613,
-0.000966788,
-0.00100749,
-0.00104765,
-0.00108717,
-0.00112597,
-0.00116397,
-0.00120108,
-0.0012372,
-0.00127227,
-0.00130617,
-0.00133884,
-0.00137017,
-0.00140008,
-0.00142848,
-0.00145528,
-0.0014804,
-0.00150374,
-0.00152522,
-0.00154475,
-0.00156225,
-0.00157763,
-0.00159081,
-0.00160171,
-0.00161024,
-0.00161633,
-0.0016199,
-0.00162088,
-0.00161917,
-0.00161472,
-0.00160744,
-0.00159729,
-0.00158419,
-0.00156807,
-0.00154888,
-0.00152655,
-0.00150103,
-0.00147227,
-0.00144021,
-0.00140482,
-0.00136604,
-0.00132384,
-0.00127818,
-0.00122903,
-0.00117635,
-0.00112013,
-0.00106033,
-0.000996946,
-0.000929956,
-0.000859348,
-0.000785117,
-0.000707261,
-0.000625779,
-0.00054068,
-0.000451952,
-0.000359651,
-0.000263788,
-0.00016436,
-6.13947e-05,
4.5076e-05,
0.000155016,
0.000268384,
0.000385134,
0.000505217,
0.000628582,
0.000755171,
0.000884923,
0.00101777,
0.00115366,
0.00129249,
0.00143421,
0.00157873,
0.00172596,
0.00187583,
0.00202822,
0.00218306,
0.00234023,
0.00249965,
0.00266119,
0.00282475,
0.00299023,
0.00315749,
0.00332643,
0.00349691,
0.00366882,
0.00384202,
0.00401639,
0.0041918,
0.0043681,
0.00454516,
0.00472285,
0.00490101,
0.00507951,
0.00525821,
0.00543695,
0.0056156,
0.005794,
0.00597201,
0.00614947,
0.00632623,
0.00650216,
0.00667708,
0.00685086,
0.00702335,
0.00719439,
0.00736383,
0.00753153,
0.00769734,
0.00786111,
0.00802269,
0.00818194,
0.00833872,
0.00849289,
0.0086443,
0.00879283,
0.00893832,
0.00908066,
0.00921971,
0.00935534,
0.00948743,
0.00961585,
0.00974049,
0.00986123,
0.00997795,
0.0100905,
0.0101989,
0.0103029,
0.0104025,
0.0104976,
0.0105881,
0.0106738,
0.0107548,
0.010831,
0.0109022,
0.0109684,
0.0110295,
0.0110855,
0.0111364,
0.011182,
0.0112224,
0.0112575,
0.0112872,
0.0113115,
0.0113305,
0.0113441,
0.0113522,
0.0113549,
0.0113522,
0.0113441,
0.0113305,
0.0113115,
0.0112872,
0.0112575,
0.0112224,
0.011182,
0.0111364,
0.0110855,
0.0110295,
0.0109684,
0.0109022,
0.010831,
0.0107548,
0.0106738,
0.0105881,
0.0104976,
0.0104025,
0.0103029,
0.0101989,
0.0100905,
0.00997795,
0.00986123,
0.00974049,
0.00961585,
0.00948743,
0.00935534,
0.00921971,
0.00908066,
0.00893832,
0.00879283,
0.0086443,
0.00849289,
0.00833872,
0.00818194,
0.00802269,
0.00786111,
0.00769734,
0.00753153,
0.00736383,
0.00719439,
0.00702335,
0.00685086,
0.00667708,
0.00650216,
0.00632623,
0.00614947,
0.00597201,
0.005794,
0.0056156,
0.00543695,
0.00525821,
0.00507951,
0.00490101,
0.00472285,
0.00454516,
0.0043681,
0.0041918,
0.00401639,
0.00384202,
0.00366882,
0.00349691,
0.00332643,
0.00315749,
0.00299023,
0.00282475,
0.00266119,
0.00249965,
0.00234023,
0.00218306,
0.00202822,
0.00187583,
0.00172596,
0.00157873,
0.00143421,
0.00129249,
0.00115366,
0.00101777,
0.000884923,
0.000755171,
0.000628582,
0.000505217,
0.000385134,
0.000268384,
0.000155016,
4.5076e-05,
-6.13947e-05,
-0.00016436,
-0.000263788,
-0.000359651,
-0.000451952,
-0.00054068,
-0.000625779,
-0.000707261,
-0.000785117,
-0.000859348,
-0.000929956,
-0.000996946,
-0.00106033,
-0.00112013,
-0.00117635,
-0.00122903,
-0.00127818,
-0.00132384,
-0.00136604,
-0.00140482,
-0.00144021,
-0.00147227,
-0.00150103,
-0.00152655,
-0.00154888,
-0.00156807,
-0.00158419,
-0.00159729,
-0.00160744,
-0.00161472,
-0.00161917,
-0.00162088,
-0.0016199,
-0.00161633,
-0.00161024,
-0.00160171,
-0.00159081,
-0.00157763,
-0.00156225,
-0.00154475,
-0.00152522,
-0.00150374,
-0.0014804,
-0.00145528,
-0.00142848,
-0.00140008,
-0.00137017,
-0.00133884,
-0.00130617,
-0.00127227,
-0.0012372,
-0.00120108,
-0.00116397,
-0.00112597,
-0.00108717,
-0.00104765,
-0.00100749,
-0.000966788,
-0.000925613,
-0.000884054,
-0.000842187,
-0.000800092,
-0.000757849,
-0.000715533,
-0.000673218,
-0.000630979,
-0.000588883,
-0.000547003,
-0.000505403,
-0.000464152,
-0.00042331,
-0.000382942,
-0.000343104,
-0.000303856,
-0.000265248,
-0.000227336,
-0.000190167,
-0.00015379,
-0.000118248,
-8.35883e-05,
-4.98479e-05,
-1.7067e-05,
1.4721e-05,
4.54842e-05,
7.51956e-05,
0.000103821,
0.000131338,
0.000157726,
0.000182964,
0.000207034,
0.000229921,
0.000251612,
0.000272099,
0.000291373,
0.00030943,
0.000326267,
0.000341885,
0.000356284,
0.000369471,
0.000381449,
0.000392231,
0.000401823,
0.00041024,
0.000417497,
0.000423608,
0.000428592,
0.00043246,
0.000435237,
0.000436865,
0.000437401,
0.000436975,
0.000435544,
0.000433151,
0.000429812,
0.000425565,
0.000420437,
0.000414464,
0.000407675,
0.000400108,
0.000391795,
0.000382774,
0.00037308,
0.000362751,
0.000351824,
0.000340339,
0.00032833,
0.000315839,
0.000302903,
0.000289559,
0.000275847,
0.000261806,
0.000247474,
0.000232892,
0.000218088,
0.000203111,
0.000187996,
0.000172781,
0.000157497,
0.000142183,
0.000126869,
0.000111594,
9.63895e-05,
8.12934e-05,
6.63317e-05,
5.15418e-05,
3.69472e-05,
2.25833e-05,
8.47105e-06,
-5.35615e-06,
-1.88794e-05,
-3.20661e-05,
-4.49012e-05,
-5.73536e-05,
-6.94109e-05,
-8.10442e-05,
-9.22439e-05,
-0.000102985,
-0.000113258,
-0.000123038,
-0.000132323,
-0.000141089,
-0.000149335,
-0.000157041,
-0.00016421,
-0.000170822,
-0.000176885,
-0.000182382,
-0.000187324,
-0.000191693,
-0.000195505,
-0.000198743,
-0.000201427,
-0.000203541,
-0.000205109,
-0.000206117,
-0.00020659,
-0.000206515,
-0.000205922,
-0.000204797,
-0.000203173,
-0.000201038,
-0.000198429,
-0.000195333,
-0.000191793,
-0.000187794,
-0.000183382,
-0.00017854,
-0.000173315,
-0.000167689,
-0.000161723,
-0.000155393,
-0.000148756,
-0.000141789,
-0.000134559,
-0.000127034,
-0.000119289,
-0.000111281,
-0.000103097,
-9.46835e-05,
-8.6137e-05,
-7.73902e-05,
-6.85565e-05,
-5.9545e-05,
-5.04935e-05,
-4.12734e-05,
-3.20611e-05,
-2.2664e-05,
-1.33229e-05,
-3.71244e-06,
5.78773e-06,
1.58964e-05,
2.58255e-05
};
+35
View File
@@ -0,0 +1,35 @@
/* Generated by rxdec_file() Octave function */
const float rxdec_coeff[]={
-0.00125472,
-0.00204605,
-0.0019897,
0.000163906,
0.00490937,
0.00986375,
0.0096718,
-0.000480351,
-0.019311,
-0.0361822,
-0.0341251,
0.000827866,
0.0690577,
0.152812,
0.222115,
0.249004,
0.222115,
0.152812,
0.0690577,
0.000827866,
-0.0341251,
-0.0361822,
-0.019311,
-0.000480351,
0.0096718,
0.00986375,
0.00490937,
0.000163906,
-0.0019897,
-0.00204605,
-0.00125472
};
+687
View File
@@ -0,0 +1,687 @@
/*---------------------------------------------------------------------------*\
FILE........: sine.c
AUTHOR......: David Rowe
DATE CREATED: 19/8/2010
Sinusoidal analysis and synthesis functions.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 1990-2010 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/*---------------------------------------------------------------------------*\
INCLUDES
\*---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "defines.h"
#include "sine.h"
#include "kiss_fft.h"
#define HPF_BETA 0.125
/*---------------------------------------------------------------------------*\
HEADERS
\*---------------------------------------------------------------------------*/
void hs_pitch_refinement(MODEL *model, COMP Sw[], float pmin, float pmax,
float pstep);
/*---------------------------------------------------------------------------*\
FUNCTIONS
\*---------------------------------------------------------------------------*/
C2CONST c2const_create(int Fs) {
C2CONST c2const;
assert((Fs == 8000) || (Fs = 16000));
c2const.Fs = Fs;
c2const.n_samp = Fs*N_S;
c2const.max_amp = floor(Fs*P_MIN_S/2);
c2const.p_min = floor(Fs*P_MIN_S);
c2const.p_max = floor(Fs*P_MAX_S);
c2const.m_pitch = floor(Fs*M_PITCH_S);
c2const.Wo_min = TWO_PI/c2const.p_max;
c2const.Wo_max = TWO_PI/c2const.p_min;
if (Fs == 8000) {
c2const.nw = 279;
} else {
c2const.nw = 511; /* actually a bit shorter in time but lets us maintain constant FFT size */
}
c2const.tw = Fs*TW_S;
fprintf(stderr, "max_amp: %d m_pitch: %d\n", c2const.n_samp, c2const.m_pitch);
fprintf(stderr, "p_min: %d p_max: %d\n", c2const.p_min, c2const.p_max);
fprintf(stderr, "Wo_min: %f Wo_max: %f\n", c2const.Wo_min, c2const.Wo_max);
fprintf(stderr, "nw: %d tw: %d\n", c2const.nw, c2const.tw);
return c2const;
}
/*---------------------------------------------------------------------------*\
FUNCTION....: make_analysis_window
AUTHOR......: David Rowe
DATE CREATED: 11/5/94
Init function that generates the time domain analysis window and it's DFT.
\*---------------------------------------------------------------------------*/
void make_analysis_window(C2CONST *c2const, codec2_fft_cfg fft_fwd_cfg, float w[], COMP W[])
{
float m;
COMP wshift[FFT_ENC];
COMP temp;
int i,j;
int m_pitch = c2const->m_pitch;
int nw = c2const->nw;
/*
Generate Hamming window centered on M-sample pitch analysis window
0 M/2 M-1
|-------------|-------------|
|-------|-------|
nw samples
All our analysis/synthsis is centred on the M/2 sample.
*/
m = 0.0;
for(i=0; i<m_pitch/2-nw/2; i++)
w[i] = 0.0;
for(i=m_pitch/2-nw/2,j=0; i<m_pitch/2+nw/2; i++,j++) {
w[i] = 0.5 - 0.5*cosf(TWO_PI*j/(nw-1));
m += w[i]*w[i];
}
for(i=m_pitch/2+nw/2; i<m_pitch; i++)
w[i] = 0.0;
/* Normalise - makes freq domain amplitude estimation straight
forward */
m = 1.0/sqrtf(m*FFT_ENC);
for(i=0; i<m_pitch; i++) {
w[i] *= m;
}
/*
Generate DFT of analysis window, used for later processing. Note
we modulo FFT_ENC shift the time domain window w[], this makes the
imaginary part of the DFT W[] equal to zero as the shifted w[] is
even about the n=0 time axis if nw is odd. Having the imag part
of the DFT W[] makes computation easier.
0 FFT_ENC-1
|-------------------------|
----\ /----
\ /
\ / <- shifted version of window w[n]
\ /
\ /
-------
|---------| |---------|
nw/2 nw/2
*/
for(i=0; i<FFT_ENC; i++) {
wshift[i].real = 0.0;
wshift[i].imag = 0.0;
}
for(i=0; i<nw/2; i++)
wshift[i].real = w[i+m_pitch/2];
for(i=FFT_ENC-nw/2,j=m_pitch/2-nw/2; i<FFT_ENC; i++,j++)
wshift[i].real = w[j];
codec2_fft(fft_fwd_cfg, wshift, W);
/*
Re-arrange W[] to be symmetrical about FFT_ENC/2. Makes later
analysis convenient.
Before:
0 FFT_ENC-1
|----------|---------|
__ _
\ /
\_______________/
After:
0 FFT_ENC-1
|----------|---------|
___
/ \
________/ \_______
*/
for(i=0; i<FFT_ENC/2; i++) {
temp.real = W[i].real;
temp.imag = W[i].imag;
W[i].real = W[i+FFT_ENC/2].real;
W[i].imag = W[i+FFT_ENC/2].imag;
W[i+FFT_ENC/2].real = temp.real;
W[i+FFT_ENC/2].imag = temp.imag;
}
}
/*---------------------------------------------------------------------------*\
FUNCTION....: hpf
AUTHOR......: David Rowe
DATE CREATED: 16 Nov 2010
High pass filter with a -3dB point of about 160Hz.
y(n) = -HPF_BETA*y(n-1) + x(n) - x(n-1)
\*---------------------------------------------------------------------------*/
float hpf(float x, float states[])
{
states[0] = -HPF_BETA*states[0] + x - states[1];
states[1] = x;
return states[0];
}
/*---------------------------------------------------------------------------*\
FUNCTION....: dft_speech
AUTHOR......: David Rowe
DATE CREATED: 27/5/94
Finds the DFT of the current speech input speech frame.
\*---------------------------------------------------------------------------*/
// TODO: we can either go for a faster FFT using fftr and some stack usage
// or we can reduce stack usage to almost zero on STM32 by switching to fft_inplace
#if 1
void dft_speech(C2CONST *c2const, codec2_fft_cfg fft_fwd_cfg, COMP Sw[], float Sn[], float w[])
{
int i;
int m_pitch = c2const->m_pitch;
int nw = c2const->nw;
for(i=0; i<FFT_ENC; i++) {
Sw[i].real = 0.0;
Sw[i].imag = 0.0;
}
/* Centre analysis window on time axis, we need to arrange input
to FFT this way to make FFT phases correct */
/* move 2nd half to start of FFT input vector */
for(i=0; i<nw/2; i++)
Sw[i].real = Sn[i+m_pitch/2]*w[i+m_pitch/2];
/* move 1st half to end of FFT input vector */
for(i=0; i<nw/2; i++)
Sw[FFT_ENC-nw/2+i].real = Sn[i+m_pitch/2-nw/2]*w[i+m_pitch/2-nw/2];
codec2_fft_inplace(fft_fwd_cfg, Sw);
}
#else
void dft_speech(codec2_fftr_cfg fftr_fwd_cfg, COMP Sw[], float Sn[], float w[])
{
int i;
float sw[FFT_ENC];
for(i=0; i<FFT_ENC; i++) {
sw[i] = 0.0;
}
/* Centre analysis window on time axis, we need to arrange input
to FFT this way to make FFT phases correct */
/* move 2nd half to start of FFT input vector */
for(i=0; i<nw/2; i++)
sw[i] = Sn[i+m_pitch/2]*w[i+m_pitch/2];
/* move 1st half to end of FFT input vector */
for(i=0; i<nw/2; i++)
sw[FFT_ENC-nw/2+i] = Sn[i+m_pitch/2-nw/2]*w[i+m_pitch/2-nw/2];
codec2_fftr(fftr_fwd_cfg, sw, Sw);
}
#endif
/*---------------------------------------------------------------------------*\
FUNCTION....: two_stage_pitch_refinement
AUTHOR......: David Rowe
DATE CREATED: 27/5/94
Refines the current pitch estimate using the harmonic sum pitch
estimation technique.
\*---------------------------------------------------------------------------*/
void two_stage_pitch_refinement(C2CONST *c2const, MODEL *model, COMP Sw[])
{
float pmin,pmax,pstep; /* pitch refinment minimum, maximum and step */
/* Coarse refinement */
pmax = TWO_PI/model->Wo + 5;
pmin = TWO_PI/model->Wo - 5;
pstep = 1.0;
hs_pitch_refinement(model,Sw,pmin,pmax,pstep);
/* Fine refinement */
pmax = TWO_PI/model->Wo + 1;
pmin = TWO_PI/model->Wo - 1;
pstep = 0.25;
hs_pitch_refinement(model,Sw,pmin,pmax,pstep);
/* Limit range */
if (model->Wo < TWO_PI/c2const->p_max)
model->Wo = TWO_PI/c2const->p_max;
if (model->Wo > TWO_PI/c2const->p_min)
model->Wo = TWO_PI/c2const->p_min;
model->L = floorf(PI/model->Wo);
/* trap occasional round off issues with floorf() */
if (model->Wo*model->L >= PI) {
model->L--;
}
assert(model->Wo*model->L < PI);
}
/*---------------------------------------------------------------------------*\
FUNCTION....: hs_pitch_refinement
AUTHOR......: David Rowe
DATE CREATED: 27/5/94
Harmonic sum pitch refinement function.
pmin pitch search range minimum
pmax pitch search range maximum
step pitch search step size
model current pitch estimate in model.Wo
model refined pitch estimate in model.Wo
\*---------------------------------------------------------------------------*/
void hs_pitch_refinement(MODEL *model, COMP Sw[], float pmin, float pmax, float pstep)
{
int m; /* loop variable */
int b; /* bin for current harmonic centre */
float E; /* energy for current pitch*/
float Wo; /* current "test" fundamental freq. */
float Wom; /* Wo that maximises E */
float Em; /* mamimum energy */
float r, one_on_r; /* number of rads/bin */
float p; /* current pitch */
/* Initialisation */
model->L = PI/model->Wo; /* use initial pitch est. for L */
Wom = model->Wo;
Em = 0.0;
r = TWO_PI/FFT_ENC;
one_on_r = 1.0/r;
/* Determine harmonic sum for a range of Wo values */
for(p=pmin; p<=pmax; p+=pstep) {
E = 0.0;
Wo = TWO_PI/p;
/* Sum harmonic magnitudes */
for(m=1; m<=model->L; m++) {
b = (int)(m*Wo*one_on_r + 0.5);
E += Sw[b].real*Sw[b].real + Sw[b].imag*Sw[b].imag;
}
/* Compare to see if this is a maximum */
if (E > Em) {
Em = E;
Wom = Wo;
}
}
model->Wo = Wom;
}
/*---------------------------------------------------------------------------*\
FUNCTION....: estimate_amplitudes
AUTHOR......: David Rowe
DATE CREATED: 27/5/94
Estimates the complex amplitudes of the harmonics.
\*---------------------------------------------------------------------------*/
void estimate_amplitudes(MODEL *model, COMP Sw[], COMP W[], int est_phase)
{
int i,m; /* loop variables */
int am,bm; /* bounds of current harmonic */
int b; /* DFT bin of centre of current harmonic */
float den; /* denominator of amplitude expression */
float r, one_on_r; /* number of rads/bin */
int offset;
COMP Am;
r = TWO_PI/FFT_ENC;
one_on_r = 1.0/r;
for(m=1; m<=model->L; m++) {
den = 0.0;
am = (int)((m - 0.5)*model->Wo*one_on_r + 0.5);
bm = (int)((m + 0.5)*model->Wo*one_on_r + 0.5);
b = (int)(m*model->Wo/r + 0.5);
/* Estimate ampltude of harmonic */
den = 0.0;
Am.real = Am.imag = 0.0;
offset = FFT_ENC/2 - (int)(m*model->Wo*one_on_r + 0.5);
for(i=am; i<bm; i++) {
den += Sw[i].real*Sw[i].real + Sw[i].imag*Sw[i].imag;
Am.real += Sw[i].real*W[i + offset].real;
Am.imag += Sw[i].imag*W[i + offset].real;
}
model->A[m] = sqrtf(den);
if (est_phase) {
/* Estimate phase of harmonic, this is expensive in CPU for
embedded devicesso we make it an option */
model->phi[m] = atan2f(Sw[b].imag,Sw[b].real);
}
}
}
/*---------------------------------------------------------------------------*\
est_voicing_mbe()
Returns the error of the MBE cost function for a fiven F0.
Note: I think a lot of the operations below can be simplified as
W[].imag = 0 and has been normalised such that den always equals 1.
\*---------------------------------------------------------------------------*/
float est_voicing_mbe(
C2CONST *c2const,
MODEL *model,
COMP Sw[],
COMP W[]
)
{
int l,al,bl,m; /* loop variables */
COMP Am; /* amplitude sample for this band */
int offset; /* centers Hw[] about current harmonic */
float den; /* denominator of Am expression */
float error; /* accumulated error between original and synthesised */
float Wo;
float sig, snr;
float elow, ehigh, eratio;
float sixty;
COMP Ew;
Ew.real = 0;
Ew.imag = 0;
sig = 1E-4;
for(l=1; l<=model->L/4; l++) {
sig += model->A[l]*model->A[l];
}
Wo = model->Wo;
error = 1E-4;
/* Just test across the harmonics in the first 1000 Hz */
int l_1000hz = model->L*1000.0/(c2const->Fs/2);
for(l=1; l<=l_1000hz; l++) {
Am.real = 0.0;
Am.imag = 0.0;
den = 0.0;
al = ceilf((l - 0.5)*Wo*FFT_ENC/TWO_PI);
bl = ceilf((l + 0.5)*Wo*FFT_ENC/TWO_PI);
/* Estimate amplitude of harmonic assuming harmonic is totally voiced */
offset = FFT_ENC/2 - l*Wo*FFT_ENC/TWO_PI + 0.5;
for(m=al; m<bl; m++) {
Am.real += Sw[m].real*W[offset+m].real;
Am.imag += Sw[m].imag*W[offset+m].real;
den += W[offset+m].real*W[offset+m].real;
}
Am.real = Am.real/den;
Am.imag = Am.imag/den;
/* Determine error between estimated harmonic and original */
offset = FFT_ENC/2 - l*Wo*FFT_ENC/TWO_PI + 0.5;
for(m=al; m<bl; m++) {
Ew.real = Sw[m].real - Am.real*W[offset+m].real;
Ew.imag = Sw[m].imag - Am.imag*W[offset+m].real;
error += Ew.real*Ew.real;
error += Ew.imag*Ew.imag;
}
}
snr = 10.0*log10f(sig/error);
if (snr > V_THRESH)
model->voiced = 1;
else
model->voiced = 0;
/* post processing, helps clean up some voicing errors ------------------*/
/*
Determine the ratio of low freqency to high frequency energy,
voiced speech tends to be dominated by low frequency energy,
unvoiced by high frequency. This measure can be used to
determine if we have made any gross errors.
*/
int l_2000hz = model->L*2000.0/(c2const->Fs/2);
int l_4000hz = model->L*4000.0/(c2const->Fs/2);
elow = ehigh = 1E-4;
for(l=1; l<=l_2000hz; l++) {
elow += model->A[l]*model->A[l];
}
for(l=l_2000hz; l<=l_4000hz; l++) {
ehigh += model->A[l]*model->A[l];
}
eratio = 10.0*log10f(elow/ehigh);
/* Look for Type 1 errors, strongly V speech that has been
accidentally declared UV */
if (model->voiced == 0)
if (eratio > 10.0)
model->voiced = 1;
/* Look for Type 2 errors, strongly UV speech that has been
accidentally declared V */
if (model->voiced == 1) {
if (eratio < -10.0)
model->voiced = 0;
/* A common source of Type 2 errors is the pitch estimator
gives a low (50Hz) estimate for UV speech, which gives a
good match with noise due to the close harmoonic spacing.
These errors are much more common than people with 50Hz3
pitch, so we have just a small eratio threshold. */
sixty = 60.0*TWO_PI/c2const->Fs;
if ((eratio < -4.0) && (model->Wo <= sixty))
model->voiced = 0;
}
//printf(" v: %d snr: %f eratio: %3.2f %f\n",model->voiced,snr,eratio,dF0);
return snr;
}
/*---------------------------------------------------------------------------*\
FUNCTION....: make_synthesis_window
AUTHOR......: David Rowe
DATE CREATED: 11/5/94
Init function that generates the trapezoidal (Parzen) sythesis window.
\*---------------------------------------------------------------------------*/
void make_synthesis_window(C2CONST *c2const, float Pn[])
{
int i;
float win;
int n_samp = c2const->n_samp;
int tw = c2const->tw;
/* Generate Parzen window in time domain */
win = 0.0;
for(i=0; i<n_samp/2-tw; i++)
Pn[i] = 0.0;
win = 0.0;
for(i=n_samp/2-tw; i<n_samp/2+tw; win+=1.0/(2*tw), i++ )
Pn[i] = win;
for(i=n_samp/2+tw; i<3*n_samp/2-tw; i++)
Pn[i] = 1.0;
win = 1.0;
for(i=3*n_samp/2-tw; i<3*n_samp/2+tw; win-=1.0/(2*tw), i++)
Pn[i] = win;
for(i=3*n_samp/2+tw; i<2*n_samp; i++)
Pn[i] = 0.0;
}
/*---------------------------------------------------------------------------*\
FUNCTION....: synthesise
AUTHOR......: David Rowe
DATE CREATED: 20/2/95
Synthesise a speech signal in the frequency domain from the
sinusodal model parameters. Uses overlap-add with a trapezoidal
window to smoothly interpolate betwen frames.
\*---------------------------------------------------------------------------*/
void synthesise(
int n_samp,
codec2_fftr_cfg fftr_inv_cfg,
float Sn_[], /* time domain synthesised signal */
MODEL *model, /* ptr to model parameters for this frame */
float Pn[], /* time domain Parzen window */
int shift /* flag used to handle transition frames */
)
{
int i,l,j,b; /* loop variables */
COMP Sw_[FFT_DEC/2+1]; /* DFT of synthesised signal */
float sw_[FFT_DEC]; /* synthesised signal */
if (shift) {
/* Update memories */
for(i=0; i<n_samp-1; i++) {
Sn_[i] = Sn_[i+n_samp];
}
Sn_[n_samp-1] = 0.0;
}
for(i=0; i<FFT_DEC/2+1; i++) {
Sw_[i].real = 0.0;
Sw_[i].imag = 0.0;
}
/* Now set up frequency domain synthesised speech */
for(l=1; l<=model->L; l++) {
b = (int)(l*model->Wo*FFT_DEC/TWO_PI + 0.5);
if (b > ((FFT_DEC/2)-1)) {
b = (FFT_DEC/2)-1;
}
Sw_[b].real = model->A[l]*cosf(model->phi[l]);
Sw_[b].imag = model->A[l]*sinf(model->phi[l]);
}
/* Perform inverse DFT */
codec2_fftri(fftr_inv_cfg, Sw_,sw_);
/* Overlap add to previous samples */
#ifdef USE_KISS_FFT
#define FFTI_FACTOR ((float)1.0)
#else
#define FFTI_FACTOR ((float32_t)FFT_DEC)
#endif
for(i=0; i<n_samp-1; i++) {
Sn_[i] += sw_[FFT_DEC-n_samp+1+i]*Pn[i] * FFTI_FACTOR;
}
if (shift)
for(i=n_samp-1,j=0; i<2*n_samp; i++,j++)
Sn_[i] = sw_[j]*Pn[i] * FFTI_FACTOR;
else
for(i=n_samp-1,j=0; i<2*n_samp; i++,j++)
Sn_[i] += sw_[j]*Pn[i] * FFTI_FACTOR;
}
/* todo: this should probably be in some states rather than a static */
static unsigned long next = 1;
int codec2_rand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
+49
View File
@@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------*\
FILE........: sine.h
AUTHOR......: David Rowe
DATE CREATED: 1/11/94
Header file for sinusoidal analysis and synthesis functions.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2009 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SINE__
#define __SINE__
#include "defines.h"
#include "comp.h"
#include "codec2_fft.h"
C2CONST c2const_create(int Fs);
void make_analysis_window(C2CONST *c2const, codec2_fft_cfg fft_fwd_cfg, float w[], COMP W[]);
float hpf(float x, float states[]);
void dft_speech(C2CONST *c2const, codec2_fft_cfg fft_fwd_cfg, COMP Sw[], float Sn[], float w[]);
void two_stage_pitch_refinement(C2CONST *c2const, MODEL *model, COMP Sw[]);
void estimate_amplitudes(MODEL *model, COMP Sw[], COMP W[], int est_phase);
float est_voicing_mbe(C2CONST *c2const, MODEL *model, COMP Sw[], COMP W[]);
void make_synthesis_window(C2CONST *c2const, float Pn[]);
void synthesise(int n_samp, codec2_fftr_cfg fftr_inv_cfg, float Sn_[], MODEL *model, float Pn[], int shift);
#define CODEC2_RAND_MAX 32767
int codec2_rand(void);
#endif
+107
View File
@@ -0,0 +1,107 @@
/* 600 - 2600 Hz FIR filter coeffs */
/* Generated by make_ssbfilt Octave script */
#define SSBFILT_N 100
float ssbfilt_coeff[]={
0.000065,
-0.000030,
0.000041,
0.000010,
-0.000128,
-0.000072,
-0.000007,
-0.000095,
-0.000063,
0.000016,
-0.000000,
0.000022,
-0.000115,
-0.000233,
-0.000023,
-0.000315,
-0.000725,
0.000073,
0.000380,
-0.000345,
0.000895,
0.002401,
0.001241,
0.001409,
0.003106,
0.001236,
-0.001117,
-0.001091,
-0.003184,
-0.005981,
-0.006904,
-0.007920,
-0.005588,
-0.002546,
-0.003476,
0.005155,
0.017465,
0.010772,
0.013033,
0.035082,
0.018466,
-0.010261,
0.016676,
0.004890,
-0.076807,
-0.055969,
-0.007360,
-0.155769,
-0.203150,
0.179458,
0.475523,
0.179458,
-0.203150,
-0.155769,
-0.007360,
-0.055969,
-0.076807,
0.004890,
0.016676,
-0.010261,
0.018466,
0.035082,
0.013033,
0.010772,
0.017465,
0.005155,
-0.003476,
-0.002546,
-0.005588,
-0.007920,
-0.006904,
-0.005981,
-0.003184,
-0.001091,
-0.001117,
0.001236,
0.003106,
0.001409,
0.001241,
0.002401,
0.000895,
-0.000345,
0.000380,
0.000073,
-0.000725,
-0.000315,
-0.000023,
-0.000233,
-0.000115,
0.000022,
-0.000000,
0.000016,
-0.000063,
-0.000095,
-0.000007,
-0.000072,
-0.000128,
0.000010,
0.000041,
-0.000030
};
+85
View File
@@ -0,0 +1,85 @@
/*---------------------------------------------------------------------------*\
FILE........: tdma.h
AUTHOR......: Brady O'Brien
DATE CREATED: 18 September 2016
Skeletion of the API for the TDMA FSK modem
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2016 Brady O'Brien
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CODEC_2_TDMA_H
#define __CODEC_2_TDMA_H
#include "fsk.h"
#include "freedv_vhf_framing.h"
//typedef void (*tdma_cb_rx_frame)()
/* The state for an individual slot */
enum slot_state {
rx_no_sync, /* Not synched */
rx_sync, /* Sunk */
tx_client, /* TX but timed from a different master */
tx_master /* TX in master mode */
};
/* The state of the entire TDMA modem */
enum tdma_state {
no_sync, /* No sync */
pilot_sync, /* Pilot modem has gotten sync, but slots haven't*/
slot_sync, /* One or more slots are sunk */
master_sync, /* This modem is the TDMA master */
};
/* TDMA frame type */
enum tdma_frame_type{
frame_master,
frame_client,
};
/* TDMA frame struct */
struct TDMA_FRAME {
enum tdma_frame_type type; /* Type of frame */
int slot_idx; /* Index of slot from where frame was rx-ed */
uint8_t frame_payload[]; /* Frame payload. TODO: figure out how to sling payloads around */
};
/* TDMA slot struct */
struct TDMA_SLOT {
struct FSK * fsk; /* The FSK modem for this slot */
enum slot_state state; /* Current local slot state */
int slot_local_frame_offset; /* Where the RX frame starts, in samples, from the perspective of the modem */
struct TDMA_SLOT * next_slot; /* Next slot in a linked list of slots */
};
/* TDMA modem */
struct TDMA_MODEM {
struct FSK * fsk_pilot; /* Pilot modem */
enum tdma_state state; /* Current state of modem */
struct TDMA_SLOT * slots; /* Linked list of slot structs */
int total_slot_count;
};
#endif
+1
View File
@@ -0,0 +1 @@
+164
View File
@@ -0,0 +1,164 @@
/* Generated by test_bits_file() Octave function */
const int test_bits[]={
0,
1,
1,
0,
0,
0,
1,
1,
0,
0,
1,
0,
1,
0,
0,
1,
0,
1,
1,
0,
0,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
1,
0,
1,
1,
0,
0,
1,
1,
1,
0,
1,
1,
0,
1,
1,
1,
1,
1,
0,
0,
1,
0,
0,
1,
1,
1,
0,
0,
1,
1,
1,
0,
0,
0,
0,
1,
1,
1,
0,
0,
1,
1,
1,
1,
1,
0,
1,
1,
1,
0,
0,
1,
1,
0,
1,
1,
1,
1,
1,
1,
1,
0,
0,
1,
1,
0,
1,
0,
0,
0,
1,
1,
1,
0,
0,
0,
0,
1,
1,
1,
1,
1,
0,
1,
1,
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
1,
1,
0,
0,
0,
1,
0,
1,
1,
1,
0,
1
};
+564
View File
@@ -0,0 +1,564 @@
/* Generated by test_bits_coh_file() Octave function */
const int test_bits_coh[]={
0,
1,
1,
0,
0,
0,
1,
1,
0,
0,
1,
0,
1,
0,
0,
1,
0,
1,
1,
0,
0,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
1,
0,
1,
1,
0,
0,
1,
1,
1,
0,
1,
1,
0,
1,
1,
1,
1,
1,
0,
0,
1,
0,
0,
1,
1,
1,
0,
0,
1,
1,
1,
0,
0,
0,
0,
1,
1,
1,
0,
0,
1,
1,
1,
1,
1,
0,
1,
1,
1,
0,
0,
1,
1,
0,
1,
1,
1,
1,
1,
1,
1,
0,
0,
1,
1,
0,
1,
0,
0,
0,
1,
1,
1,
0,
0,
0,
0,
1,
1,
1,
1,
1,
0,
1,
1,
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
1,
1,
0,
0,
0,
1,
0,
1,
1,
1,
0,
1,
1,
1,
0,
1,
0,
1,
0,
1,
0,
0,
1,
1,
0,
1,
0,
1,
1,
0,
0,
0,
1,
0,
1,
1,
1,
0,
1,
1,
1,
1,
0,
0,
0,
1,
0,
0,
0,
1,
0,
0,
0,
1,
1,
0,
0,
0,
1,
1,
0,
0,
1,
1,
1,
0,
1,
1,
0,
1,
0,
1,
0,
0,
1,
0,
1,
1,
1,
0,
0,
0,
1,
1,
1,
1,
0,
1,
0,
0,
0,
1,
1,
1,
0,
1,
1,
0,
1,
0,
0,
0,
1,
1,
1,
0,
0,
1,
1,
0,
1,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
1,
0,
1,
0,
1,
1,
0,
0,
0,
0,
1,
0,
0,
1,
0,
1,
0,
0,
0,
1,
1,
1,
0,
0,
1,
1,
1,
1,
1,
0,
1,
0,
0,
0,
0,
1,
0,
1,
1,
1,
0,
0,
0,
0,
1,
1,
0,
0,
1,
1,
1,
0,
0,
0,
0,
1,
0,
0,
1,
0,
1,
0,
1,
0,
1,
1,
0,
1,
0,
1,
1,
1,
0,
0,
1,
1,
0,
1,
0,
1,
0,
0,
1,
1,
1,
1,
1,
1,
0,
0,
0,
1,
1,
0,
0,
1,
1,
1,
1,
1,
0,
0,
0,
0,
0,
1,
0,
1,
0,
0,
0,
0,
0,
1,
0,
0,
1,
0,
0,
1,
1,
1,
0,
1,
1,
0,
0,
0,
0,
0,
1,
1,
1,
0,
1,
0,
0,
1,
1,
0,
1,
1,
0,
1,
1,
0,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
1,
1,
0,
1,
1,
0,
1,
0,
1,
0,
1,
1,
1,
0,
1,
1,
0,
1,
1,
1,
1,
0,
1,
1,
0,
1,
0,
0,
0,
0,
1,
1,
0,
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1,
1,
1,
0,
0,
1,
0,
1,
0,
1,
1,
1,
1,
1,
0,
1,
1,
1,
0,
0,
0,
1,
0,
1,
1,
1,
1,
1,
0,
1,
1,
0,
1,
0,
1,
0,
0,
0,
0,
0,
1,
1,
0,
1,
0,
0,
0,
0,
1,
1,
1,
1,
1,
0,
1,
0,
1,
1,
0,
0,
1,
1,
0,
0,
0,
0,
0,
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
1,
1,
1,
0,
0,
1,
1,
1,
0
};
+229
View File
@@ -0,0 +1,229 @@
/* Generated by test_bits_ofdm_file() Octave function */
const int test_bits_ofdm[]={
1,
1,
0,
0,
1,
1,
1,
0,
1,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
1,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
1,
1,
1,
1,
1,
1,
0,
1,
0,
1,
0,
1,
1,
0,
1,
0,
0,
0,
0,
1,
0,
1,
0,
1,
0,
1,
1,
1,
0,
1,
0,
1,
0,
1,
1,
0,
1,
1,
0,
1,
0,
0,
1,
0,
1,
0,
0,
0,
1,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
1,
1,
1,
0,
0,
1,
1,
1,
0,
0,
1,
1,
1,
0,
1,
1,
1,
1,
1,
1,
1,
1,
0,
1,
1,
1,
0,
0,
1,
1,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
1,
1,
1,
1,
0,
1,
0,
1,
1,
0,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
0,
0,
1,
1,
1,
0,
1,
0,
1,
0,
1,
1,
1,
1,
1,
1,
1,
0,
0,
1,
1,
1,
1,
0,
0,
0,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
0,
1,
1,
0,
0,
0,
1,
1,
1,
0,
1,
0,
0,
1,
1,
0,
1,
1,
0,
0,
0,
1
};
+52
View File
@@ -0,0 +1,52 @@
//==========================================================================
// Name: varicode.h
// Purpose: Varicode encoded and decode functions
// Created: Nov 24, 2012
// Authors: David Rowe
//
// License:
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.1,
// as published by the Free Software Foundation. This program is
// distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
//
//==========================================================================
#ifndef __VARICODE__
#define __VARICODE__
#ifdef __cplusplus
extern "C" {
#endif
#define VARICODE_MAX_BITS (10+2) /* max varicode bits for each ascii character */
/* 10 bits for code plus 2 0 bits for inter-character space */
struct VARICODE_DEC {
int state;
int n_zeros;
int v_len;
unsigned short packed;
int code_num;
int n_in;
int in[2];
};
int varicode_encode(short varicode_out[], char ascii_in[], int max_out, int n_in, int code_num);
void varicode_decode_init(struct VARICODE_DEC *dec_states, int code_num);
int varicode_decode(struct VARICODE_DEC *dec_states, char ascii_out[], short varicode_in[], int max_out, int n_in);
void varicode_set_code_num(struct VARICODE_DEC *dec_states, int code_num);
#ifdef __cplusplus
}
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More