I like to read. Quite often however I come across an unfamiliar word, especially while reading in a foreign language. If I am at a desk I will underline the word(s) and come back later with a dictionary to learn the meaning. However, if I’m trying to relax, lying down with a paperback, it is inconvinient to underline or write down words. I would prefer verbal note-taking, but if I just run a recorder, mainly silence is captured. I want the voice-activated recording feature of those 90s personal voice recorders on my PC. But it does not seem like a straight-forward, costless, and free solution is available. Moreover there is some demand, as seen by the five posts and partial solutions on LinuxQuestions.
So, I wrote GSquelch, which allows for the filtering-out of those silent sections automatically at run-time. A ring-buffer is employed to ensure that the dictations are not cut-off and that a lead-in and lead-out are provided to capture soft sounds which often are found at the beginning or end of phrases but are not loud enough to trigger a traditional squelch.
Currently only unsigned 8-bit mono is supported, but I will soon add support for other common formats.
Here is the C++ source code:
// gsquelch
// Christopher Merck - September 2009
//
// 21 Sept 09 - Conceptualized
// 22 Sept 09 - Implementation designed and begun
// U8 support only (low quality)
//
// TODO: 16-bit support
//
// MOTIVATION:
// While reading one often wishes to look up unfamiliar words, especially
// when working in a foreign language. However, writing can be
// distracting. Verbal note-taking is prefferable, but, if one just runs
// a recorder, mainly silence is captured. GSquelch allows for the
// filtering-out of those silent sections automatically at run-time.
// A ring-buffer is employed to ensure that the dictations are not cut-off
// and that a lead-in and lead-out are provided to capture soft sounds
// which often are found at the beginning or end of phrases but are not
// loud enough to trigger a traditional squelch.
//
// USAGE:
//
// arecord | gsquelch > out && cat out > /dev/dsp
//
// (OR)
//
// arecord | gsquelch | lame -r -s 8 -m m -b 64 --bitwidth 8 - out.mp3
//
//
#include
#include
#include
using namespace std;
class Sample
// a single sample of audio in any format
{
private:
public:
virtual float GetMagnitude ()
{
// from zero to one
}
};
class U8
// unsigned 8-bit
{
private:
unsigned char b;
public:
void Set (const U8 & s)
{
b = s.b;
}
void Read ()
{
cin >> b;
}
void Write ()
{
cout <<b class>> b;
}
void Write ()
{
cout << b;
}
const short &Get ()
{
return b;
}
float GetMagnitude ()
{
return abs (b / 32768.);
}
void Zero ()
{
b = 0;
}
};
template class FIFO
// a ring buffer
{
private:
T * buf;
T *ptr;
// number of samples and therefore squelch time-constant
int length;
// internal count of number of high samples
int high_count;
public:
// first pass threshold - the magnitude above which
// is concidered high
float thresh1;
// second pass threshold - percentage of samples which
// must be high for the buffer to be concidered high
float thresh2;
FIFO (const int length_ = 8000)
{
this->length = length_;
thresh1 = .10;
thresh2 = .05;
ptr = buf = (T *) malloc (length * sizeof (T));
if (buf == 0)
{
cerr << "ERROR: Insufficient memory" << endl;
exit (-1);
}
high_count = 0;
for (int i = 0; i thresh2)
return true;
return false;
}
bool High (T a)
// check high/low status of a sample
{
if (a.GetMagnitude () > thresh1)
return true;
return false;
}
T Push (const T & pushee)
// push an element on the front and return (pop)
// the one from the back
{
if (High (*ptr))
high_count--;
T popee = *ptr;
if (High (pushee))
high_count++;
*ptr = pushee;
ptr++;
if (ptr > buf + length * sizeof (T))
ptr = buf;
return popee;
}
};
int
main ()
{
// stdin --> squelch filter --> stdout
FIFO *ring = new FIFO ();
U8 *s = new U8 ();
//FIFO * ring = new FIFO(44100);
//S16_LE * s = new S16_LE();
long timer = 0;
while (true)
{
s->Read ();
s->Set (ring->Push (*s));
if (ring->High ())
{
timer = ring->get_length () / 2;
}
else
{
timer--;
if (timer 0)
s->Write ();
fflush (stdout);
}
return 0;
}
Do you have to source file yet ? It does not have include headers and & are replaced by & …
Comment by Mahmudul Hasan — June 5, 2011 @ 2:21 am |
Hey sorry about that! I’ll see if I can find the source once I get home in a few days. I’m actually working on a related real-time audio project so stay tuned for that!
Comment by navaburo — June 5, 2011 @ 5:06 am |
Comment by Mahmudul Hasan — June 5, 2011 @ 8:10 pm