Commit aa01e2f5 authored by Vrignault's avatar Vrignault

Version 0.73

parent 01d9aa98
This diff is collapsed.
//-------------------------------------------------------------------------
//! \file CAudioRecorder.h
//! \brief Classe de gestion du mode Enregistreur Audio
//! \author Jean-Do. Vrignault
//! Copyright (c) 2018 Vrignault Jean-Do. 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 name of the copyright holder nor the names of its 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 "ModesModifiers.h"
#include "CModeRecorder.h"
#ifndef MODEAUDIOREC
#define MODEAUDIOREC
//! \enum IDXAPARAMS
//! \brief Index of Audio Recorder mode parameters
enum IDXAPARAMS {
IDXARECORD, //!< Record status
IDXATIMER , //!< Record time
IDXASEUILR, //!< Relative detection threshold in dB (5-99)
IDXAFME , //!< Detected frequency of maximum energy
IDXANIVA , //!< Maximum level detected in numbers
IDAHBAT , //!< Internal battery charge level in %
IDXAHOUR , //!< Hour
IDXBARG , //!< Barregraph for max level
IDXMAXAREC
};
//-------------------------------------------------------------------------
//! \class CGrapheXkHz
//! \brief Management class of a graph from 0 to X kHz on n lines
//! 24 pixels high, 14 pixels for the scale and n pixels for the graph
class CGrapheXkHz
{
public:
//-------------------------------------------------------------------------
//! \brief Constructor (initialization of parameters to default values)
//! \param ife Sample frequency (48, 96 or 192 kHz)
//! \param iNLines Nb lines
//! \param y Position y from the top of the graph
CGrapheXkHz(
int ife,
int iNLines,
int y
);
//-------------------------------------------------------------------------
//! \brief Destructor
~CGrapheXkHz();
//-------------------------------------------------------------------------
//! \brief Set the sample frequency
//! \param ife Sample frequency (48, 96 or 192 kHz)
void SetFe(
int ife
);
//-------------------------------------------------------------------------
//! \brief Set the min max frequencies of the scale
//! \param iFMin Min frequency in Hz
//! \param iFMax Max frequency in Hz
void SetMinMaxScale(
int iFMin,
int iFMax
);
//-------------------------------------------------------------------------
//! \brief Initialization of the scrolling time of the graph (1s by default)
//! \param iScroll Time between two scrolls in ms
void SetTimeScroll(
int iScroll
);
//-------------------------------------------------------------------------
//! \brief Initialization of a point in the graph
//! \param iIdx Frequency index
void SetFrequence(
int iIdx
);
//-------------------------------------------------------------------------
//! \brief Print graph
void PrintGraphe();
protected:
//! Position y from the top of the graph
uint8_t iY;
//! Time between two scrolls in ms
unsigned long uiTimeScroll;
//! Next scroll time
unsigned long uiNextScroll;
//! Bitmap for the graph 128 x n points is 16 x n bytes
uint8_t *pTbGraphe;
//! Nb lines
int iNbLines;
//! Channel width in kHz
float fChannel;
//! Scale in kHz
float fScale;
//! Min and Max graph frequency in kHz
float fMinFR, fMaxFr;
//! Pixel width in kHz
float fPixel;
//! Sample frequency (48, 96 or 192 kHz)
int iFe;
//! Min scale frequencies in kHz
int iFrMin;
//! Max scale frequencies in kHz
int iFrMax;
//! Size of graphe in bytes
int iSizeGraph;
};
//-------------------------------------------------------------------------
//! \class CAudioRecorder
//! \brief Heterodyne mode management class
class CAudioRecorder: public CModeGenericRec
{
public:
//-------------------------------------------------------------------------
//! \brief Constructor (initialization of parameters to default values)
CAudioRecorder();
//-------------------------------------------------------------------------
//! \brief Creation du gestionnaire d'enregistrement
virtual void CreateRecorder();
//-------------------------------------------------------------------------
//! \brief Beginning of the mode
virtual void BeginMode();
//-------------------------------------------------------------------------
//! \brief End of the mode
virtual void EndMode();
//-------------------------------------------------------------------------
//! \brief Reading saved settings
//! \return true if OK
virtual bool ReadParams();
//-------------------------------------------------------------------------
//! \brief To display information outside of modifiers
virtual void AddPrint();
//-------------------------------------------------------------------------
//! \brief Keyboard order processing
//! If the key is a mode change key, returns the requested mode
//! This method is called regularly by the main loop
//! By default, handles modifiers
//! \param key Touch to treat
virtual int KeyManager(
unsigned short key
);
protected:
//! Maximum energie frequency in kHz
float fFME;
//! Maximum level in dB of FME in dB
int iMaxLevel;
//! Maximum level in dB
int iMemoMaxLevel;
//! Record status (PBREAK or PREC)
int iRecordMode;
//! Recording time in seconds
int iRecordTime;
//! Frequency graph
CGrapheXkHz graphe;
//! FME holding time
unsigned long uiFMEHoldingTime;
//! Time to check battery
unsigned long uiTimeCheck;
//! Width of a FFT channel in Hz
uint32_t uiFFTChannel;
//! Counter for visibility of thresold
uint8_t iCptTh;
//! Current second
uint8_t iCurrentSecond;
//! Max level
int iNivMaxBG;
};
#endif // MODEHETERODYNE
This diff is collapsed.
This diff is collapsed.
......@@ -41,13 +41,17 @@ enum IDXPARAMS {
IDXSEUILA, //!< Seuil de détection absolu en dB (-110/-30)
IDXHRECM, //!< Heterodyne recording mode
IDXHREFGR, //!< Refresh period of the heterodyne graph
IDXHLEVEL, //!< Heterodyne signal level (0.1/0.9)
IDXHDEB , //!< Heure de début
IDXHFIN , //!< Heure de fin
IDXFMIN , //!< Fréquence d'intéret minimale en Hz (1-FMax)
IDXFMAX , //!< Fréquence d'intérêt maximale en Hz (FMin-Fe/2)
IDXFMINA, //!< Fréquence d'intéret minimale en Hz (1-FMax) pour le mode audio
IDXFMAXA, //!< Fréquence d'intérêt maximale en Hz (FMin-Fe/2) pour le mode audio
IDXDMIN , //!< Durée min en secondes (1-10)
IDXDMAX , //!< Durée max en secondes (10-999)
IDXFECH , //!< Fréquence d'échantillonnage
IDXFECHA, //!< Fréquence d'échantillonnage du mode enregistreur audio
IDXGNUM , //!< Gain numérique (6, 12, 18, 24dB)
IDXFILT , //!< Filtre (O/N)
IDXHPFILT, //!< Filtre passe haut (0-25kHz)
......
......@@ -27,10 +27,6 @@ extern U8G2 *pDisplay;
// Teensy 3.6 Specific SD Card Manager
extern SdFatSdio sd;
#ifdef TESTHETFILTER
extern int iHetFilter;
#endif
//-------------------------------------------------------------------------
// Player mode management class
......@@ -43,11 +39,11 @@ const char *txtNoFile[] = {" No file! ",
const char formIDXTPLAY[] = "[&$$$$]";
const char *txtIDXTPLAY[] = {"[%s]",
"[%s]"};
const char *txtTPLAY[2][2] = {{" X10 ", "Heter"},
{" X10 ", "Heter"}};
const char *txtTPLAY[2][3] = {{" X1 ", " X10 ", " Heter "},
{" X1 ", " X10 ", " Heter "}};
const char formIDXPFHET[] = "[&$$$$$]";
const char *txtIDXPFHET[] = {"[%06.2f]",
"[%06.2f]"};
const char *txtIDXPFHET[] = {"[%06.2fk]",
"[%06.2fk]"};
// Player mode screen
// 12345678901234567890 y
......@@ -81,15 +77,15 @@ CModePlayer::CModePlayer():Reader( &paramsOperateur)
// IDXPLPLAY Play / Break Modifier
LstModifParams.push_back( new CPlayRecModifier( &iPlayBreak, true, false, 24, 9, 0, 0));
// IDXPLPOS Bargraph of the reading position
LstModifParams.push_back( new CDrawBarModifier( &iFilePercent, 76, 7, 26, 0));
LstModifParams.push_back( new CDrawBarModifier( &iFilePercent, 56, 7, 25, 1));
// IDXPLDUR Duration of the file in reading
LstModifParams.push_back( new CModificatorInt( "&$$ ", false, txtInt, &iFileDuration, 0, 9999, 1, 48, 9));
LstModifParams.push_back( new CModificatorInt( "&$$ ", false, txtInt, &iFileDuration, 0, 9999, 1, 40, 9));
// IDXPLRPOS Reading position in seconds
LstModifParams.push_back( new CModificatorInt( "&$$ ", false, txtInt, &iFilePosition, 0, 9999, 1, 0, 9));
// IDXPLTYPE Reading type, X10 or heterodyne
LstModifParams.push_back(new CEnumModifier ( formIDXTPLAY, false, true, txtIDXTPLAY, &iPlayerType, MAXPTYPE, (const char **)txtTPLAY, 79, 9));
// IDXPLTYPE Reading type, X1, X10 or heterodyne
LstModifParams.push_back( new CEnumModifier ( formIDXTPLAY, false, true, txtIDXTPLAY, &iPlayerType, MAXPTYPE, (const char **)txtTPLAY, 71, 9));
// IDXPLFRHET Heterodyne frequency
LstModifParams.push_back(new CFloatModifier( formIDXPFHET, false, txtIDXPFHET, &fHeterodyne, 8.0, 125.0, 0.25, 79, 9));
LstModifParams.push_back( new CFloatModifier( formIDXPFHET, false, txtIDXPFHET, &fHeterodyne, 8.0, 125.0, 0.25, 71, 9));
// IDXPLWAVA to IDXPLWAVD Wav file A to E
char temp[MAX_LINEPARAM+1];
for (int i=0; i<MAXLINESWAVE; i++)
......@@ -113,9 +109,6 @@ void CModePlayer::BeginMode()
{
// Call of the parent method
CModeGeneric::BeginMode();
// Heterodyne wheel ADC Initialization
ADC0Init( true);
fStepADC = 110.0 / 4096.0;
// List the wav files in the root directory
ListFiles();
// First line position
......@@ -126,6 +119,9 @@ void CModePlayer::BeginMode()
// Test battery
CheckBatteries();
uiTimeCheck = millis() + TIMECHECKBATTERY;
// Heterodyne wheel ADC Initialization
ADC0Init( true);
fStepADC = 110.0 / 4096.0;
}
//-------------------------------------------------------------------------
......@@ -144,9 +140,10 @@ void CModePlayer::AddPrint()
// Read heterodyne wheel (<1ms)
uint16_t uiVal = ADC0Read( ANALOGPINHETERODYNE);
fHeterodyne = 10.0 + (float)uiVal * fStepADC;
if (iPlayerType == TYPEX10)
//Serial.printf("fStepADC %f, uiVal %d, fHeterodyne %f\n", fStepADC, uiVal, fHeterodyne);
if (iPlayerType != TYPEHET)
{
// Mode expansion de temps X10
// Mode expansion de temps X10 ou X1
LstModifParams[IDXPLTYPE ]->SetbValid( true);
LstModifParams[IDXPLFRHET]->SetbValid(false);
}
......@@ -173,11 +170,19 @@ void CModePlayer::AddPrint()
iFilePercent = 0;
}
}
// Sample frequency display
pDisplay->setFont(u8g2_font_5x7_mf);
pDisplay->setCursor( 84, 0);
pDisplay->print( sFe);
// Restitution de la fonte normale
pDisplay->setFont(u8g2_font_6x10_mf);
if (millis() > uiTimeCheck)
{
// Test battery
CheckBatteries();
uiTimeCheck = millis() + TIMECHECKBATTERY;
// Heterodyne wheel ADC Initialization
ADC0Init( true);
}
}
......@@ -255,30 +260,14 @@ int CModePlayer::KeyManager(
StopRead();
StartRead();
}
// else change player mode (X10 / Heterodyne)
// else change player mode (X1 / X10 / Heterodyne)
else
{
if (iPlayerType != TYPEX10)
{
// Time expansion X10
iPlayerType = TYPEX10;
LstModifParams[IDXPLTYPE ]->SetbValid( true);
LstModifParams[IDXPLFRHET]->SetbValid(false);
}
else
{
// Heterodyne
iPlayerType = TYPEHET;
LstModifParams[IDXPLTYPE ]->SetbValid(false);
LstModifParams[IDXPLFRHET]->SetbValid( true);
#ifdef TESTHETFILTER
iHetFilter++;
if (iHetFilter > 3)
iHetFilter = 0;
iFilePosition = iHetFilter;
#endif
}
InitWavFile();
// Next mode
iPlayerType++;
if (iPlayerType >= MAXPTYPE)
iPlayerType = TYPEX1;
SetReadMode();
}
break;
case K_MODEB:
......@@ -310,17 +299,14 @@ bool CModePlayer::InitWavFile()
bool bOK = false;
if (lstWaveFiles.size() > 0 and iSelectedFile < (int)lstWaveFiles.size())
{
bool bExp10 = false;
if (iPlayerType == TYPEX10)
bExp10 = true;
if (CModeGeneric::bDebug)
Serial.printf("CModePlayer::InitWavFile select %d [%s]\n", iSelectedFile, lstWaveFiles[iSelectedFile].c_str());
bOK = Reader.SetWaveFile( bExp10, (char *)lstWaveFiles[iSelectedFile].c_str());
bOK = Reader.SetWaveFile( (char *)lstWaveFiles[iSelectedFile].c_str());
if (!bOK)
{
// Seconde tentative
delay(500);
bOK = Reader.SetWaveFile( bExp10, (char *)lstWaveFiles[iSelectedFile].c_str());
bOK = Reader.SetWaveFile( (char *)lstWaveFiles[iSelectedFile].c_str());
if (!bOK)
{
if (paramsOperateur.iLanguage == LFRENCH)
......@@ -330,15 +316,73 @@ bool CModePlayer::InitWavFile()
bOK = false;
}
}
// Init file Duration
if (bOK)
iFileDuration = Reader.GetWaveDuration(); // Durée max en secondes du fichier courant
else
iFileDuration = 0;
SetReadMode();
}
return bOK;
}
//-------------------------------------------------------------------------
//! \brief Set read mode
void CModePlayer::SetReadMode()
{
/* Playback modes depending on the sampling frequency
* Samp Fr Het X10 X1
* 500000 Y Y N
* 384000 Y Y N
* 250000 Y Y N
* 192000 Y Y Y
* 96000 N N Y
* 48000 N N Y
* 38400 Y Y N
* 25000 Y Y N
* 19200 Y Y N
*/
// Management of the sampling frequency
bool bHet=false, bX10=false, bX1=false, bSetX10=false;
switch (Reader.GetFe())
{
case 500000: bHet=true ; bX10=true ; bX1=false; bSetX10=true; break;
case 384000: bHet=true ; bX10=true ; bX1=false; bSetX10=true; break;
case 250000: bHet=true ; bX10=true ; bX1=false; bSetX10=true; break;
case 192000: bHet=true ; bX10=true ; bX1=true ; bSetX10=true; break;
case 96000: bHet=false; bX10=false; bX1=true ; break;
case 48000: bHet=false; bX10=false; bX1=true ; break;
case 38400: bHet=true ; bX10=true ; bX1=false; break;
case 25000: bHet=true ; bX10=true ; bX1=false; break;
case 19200: bHet=true ; bX10=true ; bX1=false; break;
}
if (iPlayerType == TYPEX10 and !bX10)
iPlayerType = TYPEX1;
else if (iPlayerType == TYPEHET and !bHet)
iPlayerType = TYPEX1;
else if (iPlayerType == TYPEX1 and !bX1)
iPlayerType = TYPEX10;
bool bSetH = false;
if (iPlayerType == TYPEHET)
bSetH = true;
Reader.SetReadMode( bSetX10, bSetH);
// Init file Duration
iFileDuration = Reader.GetWaveDuration(); // Durée max en secondes du fichier courant
// Set sample frequency string
float fFe = (float)Reader.GetFe() / 1000;
if (fFe < 47.99 or (fFe > 49.9 and fFe < 50.1))
// Forcément du X10, on restitue la bonne Fe
sprintf(sFe, "%.0fk", fFe * 10);
else
sprintf(sFe, "%.0fk", fFe);
if (bSetH)
{
LstModifParams[IDXPLTYPE ]->SetbValid(false);
LstModifParams[IDXPLFRHET]->SetbValid(true );
}
else
{
LstModifParams[IDXPLTYPE ]->SetbValid( true);
LstModifParams[IDXPLFRHET]->SetbValid(false);
}
}
//-------------------------------------------------------------------------
// Start reading the wav file
void CModePlayer::StartRead()
......
......@@ -29,6 +29,7 @@
//! \enum PLAYTYPES
//! \brief Index of Player type
enum PLAYTYPES {
TYPEX1 , //!< Normal player
TYPEX10 , //!< Time expansion X10
TYPEHET , //<! Heterodyne
MAXPTYPE
......@@ -89,6 +90,10 @@ public:
//! Return true if file OK
bool InitWavFile();
//-------------------------------------------------------------------------
//! \brief Set read mode
void SetReadMode();
//-------------------------------------------------------------------------
//! \brief Start reading the wav file
void StartRead();
......@@ -151,5 +156,8 @@ protected:
//! Gestionnaire de lecture
CReader Reader;
// Chaine de la Fe du fichier en lecture
char sFe[12];
};
#endif // MODEPLAYER
......@@ -1131,10 +1131,10 @@ CModeTestMicro::CModeTestMicro()
// Début du mode
void CModeTestMicro::BeginMode()
{
//if (CModeGeneric::bDebug)
if (CModeGeneric::bDebug)
Serial.println("CModeTestMicro::BeginMode");
// Lecture des paramètres
CGenericMode::ReadParams();
ReadParams();
// Mode protocole, on impose certains paramètres
paramsOperateur.uiDurMin = 0; // 0s pour ne pas enregistrer
paramsOperateur.uiDurMax = 0; // Durée min = durée max
......@@ -1167,23 +1167,17 @@ void CModeTestMicro::BeginMode()
// Fin du mode
void CModeTestMicro::EndMode()
{
// Appel de la méthode de base qui stoppe l'acquisition
//Serial.println("CModeTestMicro::EndMode");
// Appel de la méthode de base qui stoppe l'acquisition sans écriture des paramètres
bWriteParams = false;
CModeGenericRec::EndMode();
// On restitue les paramètres opérateur et on passe hors test micro
//Serial.println("CModeTestMicro::EndMode avant ReadParams");
ReadParams();
if (CModeGeneric::bDebug)
Serial.println("CModeTestMicro::EndMode");
Serial.println("CModeTestMicro::EndMode OK");
}
//-------------------------------------------------------------------------
// Reading saved settings
// return true if OK
bool CModeTestMicro::ReadParams()
{
// Do nothing
return true;
}
//--------------------------------------------------- ----------------------
// Affichage du mode sur l'écran
// Cette méthode est appelée régulièrement par le loop principal
......
......@@ -294,11 +294,6 @@ public:
//! \brief Fin du mode
virtual void EndMode();
//-------------------------------------------------------------------------
//! \brief Reading saved settings
//! \return true if OK
virtual bool ReadParams();
//-------------------------------------------------------------------------
//! \brief Affichage du mode sur l'écran
//! Cette méthode est appelée régulièrement par le loop principal
......
......@@ -19,9 +19,6 @@
#include <U8g2lib.h>
#include "CModeheterodyne.h"
// FME holding time
#define FMEHOLDINGTIME 5000
// Screen manager
extern U8G2 *pDisplay;
......@@ -51,6 +48,9 @@ const char *txtFrHet[] = {"HF:",
const char formIDXHHEURE[] = "&$:&$:&$";
const char *txtIDXHHEURE[] = {"%s",
"%s"};
const char formIDXLEVEL[] = "&$$";
const char *txtIDXLEVEL[] = {"L %03.1f",
"N %03.1f"};
//-------------------------------------------------------------------------
// Heterodyne mode management class
......@@ -80,7 +80,7 @@ CModeHeterodyne::CModeHeterodyne():graphe( 20, 30)
{
// Set parameters
fFreqH = 45.0;
fFME = 0.0;
fFME = 40.0;
iMaxLevel = -120;
iMemoMaxLevel = -120;
iRecordMode = PBREAK;
......@@ -125,6 +125,9 @@ void CModeHeterodyne::BeginMode()
paramsOperateur.bFiltre = false; // No low pass filter or linear filter (using DSP)
paramsOperateur.bExp10 = true; // Expansion de temps X10
paramsOperateur.iModeRecord = PHETER; // Recording mode
#ifndef GNUMONWAV
paramsOperateur.uiGainNum = GAIN0dB; // Numeric gain 0dB
#endif
if (paramsOperateur.iFreqFiltreHighPass < 10)
paramsOperateur.iFreqFiltreHighPass = 10; // Min high pass filter to 10kHz
// Call of the parent method without read params
......@@ -252,8 +255,9 @@ void CModeHeterodyne::AddPrint()
iMaxLevel = iMaxL;
iMemoMaxLevel = iMaxL;
// Get FME
fFME = fNewFME;
//Serial.printf("Det on %6.2fkHz = %ddB\n", fFME, iMaxLevel);
if (fNewFME >= 15.0 and fNewFME <= 120.0)
fFME = fNewFME;
//Serial.printf("Det on %6.2fkHz = %ddB, FMin %d\n", fFME, iMaxLevel, paramsOperateur.uiFreqMin);
// Minimum time to keep a detection
uiFMEHoldingTime = millis() + FMEHOLDINGTIME;
LstModifParams[IDXHFME ]->SetbValid( true);
......@@ -264,9 +268,6 @@ void CModeHeterodyne::AddPrint()
// No detection
//Serial.printf("No Det %ddB\n", iMaxL);
iMaxLevel = -120;
if (fFME < 0.1)
// By default, FME=40kHz, else, last FME
fFME = 40.0;
uiFMEHoldingTime = millis() + FMEHOLDINGTIME;
LstModifParams[IDXHFME ]->SetbValid( false);
LstModifParams[IDXHNIVA]->SetbValid( false);
......@@ -300,15 +301,6 @@ void CModeHeterodyne::AddPrint()
else if (paramsOperateur.uiGainNum < 4)
((CRecorderH *)pRecorder)->SetShiftHeterodyne(4 - paramsOperateur.uiGainNum);
#endif
/*if (iMaxLevel > -120)
{
// Set FME on graph on 3 pixels
//graphe.SetFrequence( ((int)fFME)-1);
<