[DEV] add parameters to heve a good recorder application

This commit is contained in:
Edouard DUPIN 2019-01-09 23:42:55 +01:00
parent 008eac96d9
commit 6bbe793e3f
23 changed files with 357 additions and 65 deletions

View File

@ -8,6 +8,6 @@
int32_t appl::getLogId() {
static int32_t g_val = elog::registerInstance("RecoWord");
static int32_t g_val = elog::registerInstance("audio-reco-analyser");
return g_val;
}

View File

@ -0,0 +1,38 @@
audio-reco
==========
`audio-reco` is simple audio recognition engine build from scratch
Instructions
============
Note:
depend on etk library (MPL v2.0)
To create a corpus:
lutin.py audio-reco-wordRecorder?build?run
Analyse the corpus and create the "model":
lutin.py audio-reco-analyser?build?run:--corpus=~/.local/shared/audio-reco-wordRecorder/corpus
lutin.py audio-reco-analyser?build?run:--corpus=~/.local/shared/audio-reco-wordRecorder/corpus:--help
lutin -cclang -mrelease audio-reco-wordRecorder?build?run:--elog-level=3:--user_name=Edouard_DUPIN:--user_birth_year=1983:--source_type=ORDERED_WORD
License (MPL v2.0)
=====================
Copyright audio Edouard DUPIN
Licensed under the Mozilla Public License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.mozilla.org/MPL/2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -13,14 +13,51 @@
#include <etk/tool.hpp>
#include <appl/wordList_FR.hpp>
#include <appl/wordList_FR_ordered.hpp>
#include <appl/wordList_FR_selected.hpp>
#include <appl/wordList_number.hpp>
#include <etk/typeInfo.hpp>
ETK_DECLARE_TYPE(appl::Windows);
ETK_DECLARE_TYPE(appl::wordMode);
appl::Windows::Windows() :
propertyCount(this, "count",
5,
"Number of time we restart a record"),
propertyInput(this, "input",
"microphone",
"play microphone stream",
&appl::Windows::inputChangeValue),
propertyRandom(this, "random",
false,
"play in random mode"),
propertyCorpusPath(this, "corpus-path",
"USER_DATA:///corpus/" + etk::toString(echrono::Clock::now()),
"corpus root path"),
propertyUserName(this, "user-name",
"Unknow",
"User name to identify the corpus source"),
propertyUserBirthYear(this, "user-year",
0,
"Birth year of the user to distingush the age of the user"),
propertyWordMode(this, "word-mode",
appl::wordMode::wordMode_ALL_WORD,
"Word list mode"),
m_composer(null) {
addObjectType("appl::Windows");
propertyTitle.setDirectCheck("River IO viewer");
// set property list:
propertyWordMode.add(appl::wordMode::wordMode_ALL_WORD, "ALL_WORD");
propertyWordMode.add(appl::wordMode::wordMode_ORDERED_WORD, "ORDERED_WORD");
propertyWordMode.add(appl::wordMode::wordMode_SELECTED_WORD, "SELECTED_WORD");
propertyWordMode.add(appl::wordMode::wordMode_NUMBER, "NUMBER");
}
void appl::Windows::inputChangeValue() {
ememory::SharedPtr<appl::widget::DataViewer> tmpDisp = ememory::dynamicPointerCast<appl::widget::DataViewer>(getSubObjectNamed("displayer"));
if (tmpDisp != null) {
tmpDisp->propertyInput.set(propertyInput.get());
}
}
void appl::Windows::init() {
@ -39,6 +76,11 @@ void appl::Windows::init() {
composition += " Reset Currrent Record\n";
composition += " </label>\n";
composition += " </button>\n";
composition += " <button name='bt-next' expand='false,true' fill='true'>\n";
composition += " <label>\n";
composition += " Next\n";
composition += " </label>\n";
composition += " </button>\n";
composition += " </sizer>\n";
composition += " <label name='text-to-say' expand='true' fill='true' font-size='75'>\n";
composition += " Text to say ...\n";
@ -48,7 +90,7 @@ void appl::Windows::init() {
m_composer = ewol::widget::Composer::create();
if (m_composer == null) {
APPL_CRITICAL(" An error occured ... in the windows creatrion ...");
APPL_CRITICAL(" An error occured ... in the windows creation ...");
return;
}
APPL_ERROR("Composer LOAD [BEGIN]");
@ -57,15 +99,17 @@ void appl::Windows::init() {
APPL_ERROR("Composer LOAD [ END ]");
subBind(ewol::widget::Button, "bt-record", signalPressed, sharedFromThis(), &appl::Windows::onCallbackRecord);
subBind(ewol::widget::Button, "bt-reset", signalPressed, sharedFromThis(), &appl::Windows::onCallbackGenerate);
subBind(ewol::widget::Button, "bt-next", signalPressed, sharedFromThis(), &appl::Windows::resetCount);
subBind(ewol::widget::Button, "bt-next", signalPressed, sharedFromThis(), &appl::Windows::next);
subBind(appl::widget::DataViewer, "displayer", signalFinished, sharedFromThis(), &appl::Windows::onCallbackFinished);
next();
}
void appl::Windows::onCallbackFinished() {
APPL_INFO("Recording is finished");
ememory::SharedPtr<appl::widget::DataViewer> tmpDisp = ememory::dynamicPointerCast<appl::widget::DataViewer>(getSubObjectNamed("displayer"));
if (tmpDisp != null) {
tmpDisp->store("Edouard DUPIN", m_list[m_listPos], "FR_fr");
tmpDisp->store(propertyCorpusPath.get(), propertyUserName.get(), propertyUserBirthYear.get(), m_textToSay, "FR_fr");
m_count++;
if (m_count >= propertyCount.get()) {
m_count = 0;
@ -77,6 +121,10 @@ void appl::Windows::onCallbackFinished() {
}
}
void appl::Windows::resetCount() {
m_count = 0;
}
void appl::Windows::onCallbackRecord() {
APPL_INFO("Start/stop Record of data");
ememory::SharedPtr<appl::widget::DataViewer> tmpDisp = ememory::dynamicPointerCast<appl::widget::DataViewer>(getSubObjectNamed("displayer"));
@ -85,6 +133,14 @@ void appl::Windows::onCallbackRecord() {
}
}
void appl::Windows::stop() {
APPL_INFO("stop Record of data");
ememory::SharedPtr<appl::widget::DataViewer> tmpDisp = ememory::dynamicPointerCast<appl::widget::DataViewer>(getSubObjectNamed("displayer"));
if (tmpDisp != null) {
tmpDisp->stop();
}
}
void appl::Windows::onCallbackGenerate() {
ememory::SharedPtr<appl::widget::DataViewer> tmpDisp = ememory::dynamicPointerCast<appl::widget::DataViewer>(getSubObjectNamed("displayer"));
if (tmpDisp != null) {
@ -97,21 +153,44 @@ void appl::Windows::onCallbackGenerate() {
void appl::Windows::next() {
m_total++;
m_listPos++;
#if 0
if (m_listPos >= m_list.size()) {
m_listPos = 0;
m_list.clear();
while (m_list.size() == 0) {
int32_t id = appl::wordList::getRandWord_FR();
if (appl::wordList::getWord_FR(id).size() > 5 ) {
m_list.pushBack(appl::wordList::getWord_FR(id));
}
int32_t id = m_listPos-1;
if (propertyWordMode.get() == wordMode_ALL_WORD) {
if (propertyRandom.get() == false) {
if (id >= appl::wordList::getWord_FR_count()) {
stop();
}
} else {
id = appl::wordList::getRandWord_FR();
}
configureNewText(m_list[m_listPos]);
#else
configureNewText(appl::wordList::getWord_FR_ordered(m_listPos-1));
#endif
configureNewText(appl::wordList::getWord_FR(id));
} else if (propertyWordMode.get() == wordMode_ORDERED_WORD) {
if (propertyRandom.get() == false) {
if (id >= appl::wordList::getWord_FR_ordered_count()) {
stop();
}
} else {
id = appl::wordList::getRandWord_FR_ordered();
}
configureNewText(appl::wordList::getWord_FR_ordered(id));
} else if (propertyWordMode.get() == wordMode_NUMBER) {
if (propertyRandom.get() == false) {
if (id >= appl::wordList::getWord_number_count()) {
stop();
}
} else {
id = appl::wordList::getRandWord_number();
}
configureNewText(appl::wordList::getWord_number(id));
} else if (propertyWordMode.get() == wordMode_SELECTED_WORD) {
if (propertyRandom.get() == false) {
if (id >= appl::wordList::getWord_FR_selected_count()) {
stop();
}
} else {
id = appl::wordList::getRandWord_FR_selected();
}
configureNewText(appl::wordList::getWord_FR_selected(id));
}
}
void appl::Windows::updateCurentLabel() {

View File

@ -9,9 +9,21 @@
#include <ewol/widget/Composer.hpp>
namespace appl {
enum wordMode {
wordMode_ALL_WORD,
wordMode_ORDERED_WORD,
wordMode_NUMBER,
wordMode_SELECTED_WORD,
};
class Windows : public ewol::widget::Windows {
public:
eproperty::Value<int32_t> propertyCount;
eproperty::Value<etk::String> propertyInput;
eproperty::Value<bool> propertyRandom;
eproperty::Value<etk::Uri> propertyCorpusPath;
eproperty::Value<etk::String> propertyUserName;
eproperty::Value<int32_t> propertyUserBirthYear;
eproperty::List<enum wordMode> propertyWordMode;
private:
ememory::SharedPtr<ewol::widget::Composer> m_composer;
protected:
@ -23,21 +35,16 @@ namespace appl {
void onCallbackRecord();
void onCallbackGenerate();
void onCallbackFinished();
void resetCount();
void stop();
etk::String m_textToSay;
etk::Vector<etk::String> m_list = {
"",/*
"bonjour", */"ordinateur", "oui", "non", /*"démarre", "arrête", "joue",
"suivant", "suivante", "précédent", "précédente", "heure", "jour", "moi", "année",
"ne", "pas", "est",
"maître", "esclave",*/
"quelle", "quel", "comment", "pourquoi",
"zoo", "wagon", "téléphone", "télévision", "appel", "film", "musique", "vidéo", "annimation", "enfant", "adulte"};
int32_t m_listPos = 0;
int32_t m_count = 0;
int32_t m_total = 0;
void configureNewText(const etk::String& _text);
void next();
void updateCurentLabel();
void inputChangeValue();
};
}

View File

@ -8,6 +8,6 @@
int32_t appl::getLogId() {
static int32_t g_val = elog::registerInstance("RecoWord");
static int32_t g_val = elog::registerInstance("audio-reco-wordRecorder");
return g_val;
}

View File

@ -43,6 +43,21 @@ static const etk::String configurationRiver =
" }\n"
"}\n";
static void usage() {
APPL_PRINT(" --random/-r Random record words (instead of ordered)");
APPL_PRINT(" --input=XXX Audio source");
APPL_PRINT(" microphone default Io of the backend (default)");
APPL_PRINT(" microphone_USB alsa hw1,0 input");
APPL_PRINT(" --source_type=XXX Record specific word source");
APPL_PRINT(" ALL_WORD All french word availlable (default)");
APPL_PRINT(" ORDERED_WORD The 1500 more used word");
APPL_PRINT(" NUMBER Say mumber -5 to 100 and 1k 1M 1B 1T ...");
APPL_PRINT(" SELECTED_WORD small list of selected word");;
APPL_PRINT(" --user_name=\"XXX\" Name of the user");
APPL_PRINT(" --user_birth_year=XXX Birth year of the speaker");
APPL_PRINT(" --corpus_root_path=XXX Root path of the corpus (add after a folder with the name and other informations");
exit(0);
}
class MainApplication : public ewol::context::Application {
public:
@ -52,15 +67,14 @@ class MainApplication : public ewol::context::Application {
etk::String tmpppp = _context.getCmd().get(iii);
if ( tmpppp == "-h"
|| tmpppp == "--help") {
//APPL_PRINT(" --ctags=xxx c-flags-file-name" );
exit(0);
}
usage();
}
}
etk::theme::setName("COLOR", "color/white/");
_context.setSize(vec2(800, 600));
_context.setSize(vec2(900, 600));
_context.setTitle("edn");
_context.setTitle("audio-reco-wordRecorder");
// select internal data for font ...
_context.getFontDefault().setUseExternal(true);
@ -88,7 +102,7 @@ class MainApplication : public ewol::context::Application {
appl::widget::DataViewer::createManagerWidget(_context.getWidgetManager());
ememory::SharedPtr<ewol::widget::Windows> basicWindows = appl::Windows::create();
ememory::SharedPtr<appl::Windows> basicWindows = appl::Windows::create();
if (basicWindows == null) {
APPL_ERROR("Can not allocate the basic windows");
_context.exit(-1);
@ -99,33 +113,48 @@ class MainApplication : public ewol::context::Application {
// add files
APPL_INFO("show list of files : ");
/*
for( int32_t iii=0 ; iii<_context.getCmd().size(); iii++) {
etk::String tmpppp = _context.getCmd().get(iii);
if (tmpppp.startWith("--ctags=") == true) {
etk::String name = tmpppp.extract(8);
APPL_INFO("Load ctag file : \"" << name << "\"" );
appl::setCtagsFileName(name);
} else if ( tmpppp == "-h"
|| tmpppp == "--help") {
if ( tmpppp == "-h"
|| tmpppp == "--help") {
// nothing to do ...
} else {
etk::Path file(tmpppp);
if (etk::path::isFile(file) == true) {
APPL_INFO("need load file : \"" << file << "\"" );
m_bufferManager->open(file);
} else if (etk::path::isDirectory(file) == true) {
etk::Vector<etk::Path> listOfFiles = etk::path::list(file, etk::path::LIST_FILE);
for (auto &it: listOfFiles) {
if (etk::path::isFile(it) == true) {
APPL_INFO("need load file : \"" << it << "\"" );
m_bufferManager->open(it);
}
}
} else if ( tmpppp == "--random"
|| tmpppp == "-r") {
// random display word
APPL_ERROR("SET mode RANDOM");
basicWindows->propertyRandom.set(true);
} else if (tmpppp.startWith("--source_type=") == true) {
etk::String mode = tmpppp.extract(14);
if (mode == "ALL_WORD") {
basicWindows->propertyWordMode.set(appl::wordMode_ALL_WORD);
} else if (mode == "ORDERED_WORD") {
basicWindows->propertyWordMode.set(appl::wordMode_ORDERED_WORD);
} else if (mode == "NUMBER") {
basicWindows->propertyWordMode.set(appl::wordMode_NUMBER);
} else if (mode == "SELECTED_WORD") {
basicWindows->propertyWordMode.set(appl::wordMode_SELECTED_WORD);
} else {
APPL_ERROR("Can not select mode in list: '" << mode << "'" );
usage();
}
} else if (tmpppp.startWith("--input=") == true) {
etk::String input = tmpppp.extract(8);
basicWindows->propertyInput.set(input);
} else if (tmpppp.startWith("--user_name=") == true) {
etk::String userName = tmpppp.extract(12);
basicWindows->propertyUserName.set(userName);
} else if (tmpppp.startWith("--user_birth_year=") == true) {
etk::String userBirthDate = tmpppp.extract(18);
basicWindows->propertyUserBirthYear.set(etk::string_to_int32_t(userBirthDate));
} else if (tmpppp.startWith("--corpus_root_path=") == true) {
etk::Path corpusPath = tmpppp.extract(19);
basicWindows->propertyCorpusPath.set(corpusPath);
} else {
APPL_ERROR("Unknow parameter: '" << tmpppp << "'" );
//usage();
}
}
*/
basicWindows->next();
APPL_INFO("==> START ... (END)");
return;
}

View File

@ -9,6 +9,9 @@
#include <etk/tool.hpp>
#include <ewol/object/Manager.hpp>
#include <etk/typeInfo.hpp>
ETK_DECLARE_TYPE(appl::widget::DataViewer);
static const int32_t nbSecondOffset = 3;
static const float nbSecondSilence = 1.1;
static const int32_t nbSecond = 10;
@ -19,6 +22,9 @@ static const float stopThresholdLevel = 0.1;
appl::widget::DataViewer::DataViewer() :
propertyInput(this, "input",
"microphone",
"play microphone stream"),
m_minVal(-1.0f),
m_maxVal(1.0f),
m_sampleRate(48000) {
@ -90,7 +96,7 @@ void appl::widget::DataViewer::start() {
m_interface = m_manager->createInput(m_sampleRate,
channel,
audio::format_int16,
"microphone_USB");
propertyInput.get());
if(m_interface == null) {
APPL_ERROR("null interface");
return;
@ -307,14 +313,19 @@ bool appl::widget::DataViewer::onEventInput(const ewol::event::Input& _event) {
}
void appl::widget::DataViewer::store(const etk::String& _userName, const etk::String& _value, const etk::String& _language) {
void appl::widget::DataViewer::store(const etk::Uri& _baseUri, const etk::String& _userName, int32_t _userYearBirth, const etk::String& _value, const etk::String& _language) {
if (m_data16.size() == 0) {
return;
}
etk::String baseName = _language + "_" + _userName + "_" + etk::toString(m_time.get());
// create the buffer
ejson::Document doc;
doc.add("user", ejson::String(_userName));
if (_userName != "") {
doc.add("user", ejson::String(_userName));
}
if (_userYearBirth != 0) {
doc.add("user-birth-year", ejson::Number(_userYearBirth));
}
doc.add("value", ejson::String(_value));
doc.add("language", ejson::String(_language));
doc.add("time", ejson::Number(m_time.get()));
@ -323,26 +334,27 @@ void appl::widget::DataViewer::store(const etk::String& _userName, const etk::St
doc.add("audio_sample_rate", ejson::Number(48000));
doc.add("audio_filename", ejson::String(baseName + ".raw"));
etk::Uri uriMetaData = _baseUri;
uriMetaData.setPath(_baseUri.getPath() / (baseName + ".json"));
doc.storeSafe(uriMetaData);
APPL_WARNING("store: " << uriMetaData);
etk::String fileNameMetaData = "USER_DATA:///corpus/" + baseName + ".json";
doc.storeSafe(etk::Uri(fileNameMetaData));
APPL_WARNING("store: " << fileNameMetaData);
etk::String fileNameAudioFile = "USER_DATA:///corpus/" + baseName + ".raw";
etk::Uri uriAudioFile = _baseUri;
uriAudioFile.setPath(_baseUri.getPath() / (baseName + ".raw"));
int64_t posStart = int64_t(m_detectStartPosition)-nbSecondPreviousPost*m_sampleRate;
posStart = etk::avg(int64_t(0), posStart, int64_t(m_data.size()));
int64_t posStop = int64_t(m_detectStopPosition)+nbSecondPreviousPost*m_sampleRate;
posStop = etk::avg(int64_t(0), posStop, int64_t(m_data.size()));
{
ememory::SharedPtr<etk::io::Interface> fileIO = etk::uri::get(fileNameAudioFile);
ememory::SharedPtr<etk::io::Interface> fileIO = etk::uri::get(uriAudioFile);
if (fileIO->open(etk::io::OpenMode::Write) == false) {
return;
}
fileIO->write(&m_data16[posStart], 1*audio::getFormatBytes(audio::format_int16), (posStop-posStart));
fileIO->close();
}
APPL_WARNING("store: " << fileNameAudioFile);
APPL_WARNING("store: " << uriAudioFile);
reset();
}

View File

@ -17,6 +17,7 @@ namespace appl {
class DataViewer : public ewol::Widget {
public:
esignal::Signal<> signalFinished;
eproperty::Value<etk::String> propertyInput;
private:
mutable ethread::MutexRecursive m_mutex;
private:
@ -52,7 +53,7 @@ namespace appl {
public:
void onDraw() override;
void onRegenerateDisplay() override;
void store(const etk::String& _userName, const etk::String& _value, const etk::String& _language);
void store(const etk::Uri& _baseUri, const etk::String& _userName, int32_t _userYearBirth, const etk::String& _value, const etk::String& _language);
protected:
esignal::Connection m_PCH; //!< Periodic Call Handle to remove it when needed
/**

View File

@ -341212,3 +341212,10 @@ int32_t appl::wordList::getRandWord_FR() {
return etk::tool::irand(0, wordListSize-1);
}
int32_t appl::wordList::getWord_FR_count() {
return wordListSize;
}

View File

@ -10,5 +10,6 @@ namespace appl {
namespace wordList {
etk::String getWord_FR(int32_t _id);
int32_t getRandWord_FR();
int32_t getWord_FR_count();
};
}

View File

@ -0,0 +1,61 @@
/** @file
* @author Edouard DUPIN
* @copyright 2019, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <ewol/ewol.hpp>
#include <appl/debug.hpp>
#include <appl/wordList_FR_selected.hpp>
#include <etk/tool.hpp>
static const char* myWordList[] = {
"bonjour",
"ordinateur",
"oui",
"non",
"démare",
"arrête",
"joue",
"suivant",
"précédent",
"précédente",
"heure",
"jour",
"moi",
"année",
"ne",
"pas",
"est",
"maître",
"esclave",
"quelle",
"quel",
"comment",
"pourquoi",
"zoo",
"wagon",
"téléphone",
"télévision",
"appel",
"film",
"musique",
"vidéo",
"annimation",
"enfant",
"adulte"
};
static int32_t wordListSize = sizeof(myWordList)/sizeof(char*);
etk::String appl::wordList::getWord_FR_selected(int32_t _id) {
return myWordList[_id];
}
int32_t appl::wordList::getRandWord_FR_selected() {
return etk::tool::irand(0, wordListSize-1);
}
int32_t appl::wordList::getWord_FR_selected_count() {
return wordListSize;
}

View File

@ -0,0 +1,15 @@
/** @file
* @author Edouard DUPIN
* @copyright 2019, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/types.hpp>
namespace appl {
namespace wordList {
etk::String getWord_FR_selected(int32_t _id);
int32_t getRandWord_FR_selected();
int32_t getWord_FR_selected_count();
};
}

View File

@ -0,0 +1,25 @@
/** @file
* @author Edouard DUPIN
* @copyright 2019, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <ewol/ewol.hpp>
#include <appl/debug.hpp>
#include <appl/wordList_number.hpp>
#include <etk/tool.hpp>
static int32_t wordListSize = 2000000000;
etk::String appl::wordList::getWord_number(int32_t _id) {
return etk::toString(_id);
}
int32_t appl::wordList::getRandWord_number() {
return etk::tool::irand(0, wordListSize-1);
}
int32_t appl::wordList::getWord_number_count() {
return wordListSize;
}

View File

@ -0,0 +1,15 @@
/** @file
* @author Edouard DUPIN
* @copyright 2019, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/types.hpp>
namespace appl {
namespace wordList {
etk::String getWord_number(int32_t _id);
int32_t getRandWord_number();
int32_t getWord_number_count();
};
}

View File

@ -30,7 +30,9 @@ def configure(target, my_module):
'appl/Windows.cpp',
'appl/widget/DataViewer.cpp',
'appl/wordList_FR.cpp',
'appl/wordList_FR_ordered.cpp'
'appl/wordList_FR_ordered.cpp',
'appl/wordList_FR_selected.cpp',
'appl/wordList_number.cpp',
])
my_module.add_depend(['ewol', 'audio-river'])
my_module.add_path(".")