diff --git a/recoWord/__pycache__/lutin_recoWord.cpython-37.pyc b/recoWord/__pycache__/lutin_recoWord.cpython-37.pyc new file mode 100644 index 0000000..4293854 Binary files /dev/null and b/recoWord/__pycache__/lutin_recoWord.cpython-37.pyc differ diff --git a/recoWord/appl/Windows.cpp b/recoWord/appl/Windows.cpp new file mode 100644 index 0000000..75253b6 --- /dev/null +++ b/recoWord/appl/Windows.cpp @@ -0,0 +1,116 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2019, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include + +appl::Windows::Windows() : + propertyCount(this, "count", + 5, + "Number of time we restart a record"), + m_composer(null) { + addObjectType("appl::Windows"); + propertyTitle.setDirectCheck("River IO viewer"); +} + +void appl::Windows::init() { + ewol::widget::Windows::init(); + APPL_ERROR("Load Application"); + etk::String composition = etk::String(""); + composition += "\n"; + composition += " \n"; + composition += " \n"; + composition += " \n"; + composition += " \n"; + composition += " \n"; + composition += " \n"; + composition += "\n"; + + m_composer = ewol::widget::Composer::create(); + if (m_composer == null) { + APPL_CRITICAL(" An error occured ... in the windows creatrion ..."); + return; + } + APPL_ERROR("Composer LOAD [BEGIN]"); + m_composer->loadFromString(composition); + setSubWidget(m_composer); + 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(appl::widget::DataViewer, "displayer", signalFinished, sharedFromThis(), &appl::Windows::onCallbackFinished); + next(); +} + +void appl::Windows::onCallbackFinished() { + APPL_INFO("Recording is finished"); + ememory::SharedPtr tmpDisp = ememory::dynamicPointerCast(getSubObjectNamed("displayer")); + if (tmpDisp != null) { + tmpDisp->store("Edouard DUPIN", m_list[m_listPos], "FR_fr"); + m_count++; + if (m_count >= propertyCount.get()) { + m_count = 0; + next(); + } else { + updateCurentLabel(); + tmpDisp->recordToggle(); + } + } +} + +void appl::Windows::onCallbackRecord() { + APPL_INFO("Start/stop Record of data"); + ememory::SharedPtr tmpDisp = ememory::dynamicPointerCast(getSubObjectNamed("displayer")); + if (tmpDisp != null) { + tmpDisp->recordToggle(); + } +} + +void appl::Windows::onCallbackGenerate() { + ememory::SharedPtr tmpDisp = ememory::dynamicPointerCast(getSubObjectNamed("displayer")); + if (tmpDisp != null) { + tmpDisp->stop(); + tmpDisp->reset(); + tmpDisp->start(); + } +} + +void appl::Windows::next() { + m_listPos++; + if (m_listPos >= m_list.size()) { + m_listPos = 0; + return; + } + configureNewText(m_list[m_listPos]); +} + +void appl::Windows::updateCurentLabel() { + auto elem = ememory::dynamicPointerCast(getSubObjectNamed("text-to-say")); + if (elem == null) { + return; + } + elem->propertyValue.set("[" + etk::toString(m_count+1) + "/" + etk::toString(propertyCount.get()) + "] "+ m_textToSay); +} + +void appl::Windows::configureNewText(const etk::String& _text) { + m_textToSay = _text; + updateCurentLabel(); + onCallbackGenerate(); +} diff --git a/recoWord/appl/Windows.hpp b/recoWord/appl/Windows.hpp new file mode 100644 index 0000000..b00d1e0 --- /dev/null +++ b/recoWord/appl/Windows.hpp @@ -0,0 +1,41 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2019, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +namespace appl { + class Windows : public ewol::widget::Windows { + public: + eproperty::Value propertyCount; + private: + ememory::SharedPtr m_composer; + protected: + Windows(); + void init() override; + public: + DECLARE_FACTORY(Windows); + public: // callback functions + void onCallbackRecord(); + void onCallbackGenerate(); + void onCallbackFinished(); + etk::String m_textToSay; + etk::Vector m_list = { + "", + //"bonjour", "ordinateur", "démarre", "arrête", "joue", + //"suivant", "suivante", "précédent", "précédente", "heure", "jour", "moi", "année", + "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; + void configureNewText(const etk::String& _text); + void next(); + void updateCurentLabel(); + }; +} + diff --git a/recoWord/appl/debug.cpp b/recoWord/appl/debug.cpp new file mode 100644 index 0000000..93b4d60 --- /dev/null +++ b/recoWord/appl/debug.cpp @@ -0,0 +1,13 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2019, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + + +int32_t appl::getLogId() { + static int32_t g_val = elog::registerInstance("RecoWord"); + return g_val; +} diff --git a/recoWord/appl/debug.hpp b/recoWord/appl/debug.hpp new file mode 100644 index 0000000..8b24de3 --- /dev/null +++ b/recoWord/appl/debug.hpp @@ -0,0 +1,39 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2019, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include + +namespace appl { + int32_t getLogId(); +} + +#define APPL_BASE(info,data) ELOG_BASE(appl::getLogId(),info,data) + +#define APPL_PRINT(data) APPL_BASE(-1, data) +#define APPL_CRITICAL(data) APPL_BASE(1, data) +#define APPL_ERROR(data) APPL_BASE(2, data) +#define APPL_WARNING(data) APPL_BASE(3, data) +#ifdef DEBUG + #define APPL_INFO(data) APPL_BASE(4, data) + #define APPL_DEBUG(data) APPL_BASE(5, data) + #define APPL_VERBOSE(data) APPL_BASE(6, data) + #define APPL_TODO(data) APPL_BASE(4, "TODO : " << data) +#else + #define APPL_INFO(data) do { } while(false) + #define APPL_DEBUG(data) do { } while(false) + #define APPL_VERBOSE(data) do { } while(false) + #define APPL_TODO(data) do { } while(false) +#endif + +#define APPL_ASSERT(cond,data) \ + do { \ + if (!(cond)) { \ + APPL_CRITICAL(data); \ + assert(!#cond); \ + } \ + } while (0) + diff --git a/recoWord/appl/main.cpp b/recoWord/appl/main.cpp new file mode 100644 index 0000000..3fe4af9 --- /dev/null +++ b/recoWord/appl/main.cpp @@ -0,0 +1,140 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2019, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static const etk::String configurationRiver = + "{\n" + " microphone:{\n" + " io:'input',\n" + " map-on:{\n" + " interface:'auto',\n" + " name:'default',\n" + " },\n" + " frequency:48000,\n" + " channel-map:['front-left', 'front-right'],\n" + " type:'auto',\n" + " nb-chunk:1024\n" + " }\n" + "}\n"; + + +class MainApplication : public ewol::context::Application { + public: + virtual void onCreate(ewol::Context& _context) override { + APPL_INFO(" == > CREATE ... (START) [" << gale::getBoardType() << "] (" << gale::getCompilationMode() << ") (BEGIN)"); + for( int32_t iii=0 ; iii<_context.getCmd().size(); iii++) { + etk::String tmpppp = _context.getCmd().get(iii); + if ( tmpppp == "-h" + || tmpppp == "--help") { + //APPL_PRINT(" --ctags=xxx c-flags-file-name" ); + exit(0); + } + } + etk::theme::setName("COLOR", "color/white/"); + + _context.setSize(vec2(800, 600)); + + _context.setTitle("edn"); + + // select internal data for font ... + _context.getFontDefault().setUseExternal(true); + #ifdef __TARGET_OS__Android + _context.getFontDefault().set("FreeSerif", 19); + #else + _context.getFontDefault().set("FreeSerif;DejaVuSansMono",14); + #endif + + // set the application icon ... + //_context.setIcon("DATA:///icon.png"); + APPL_INFO("==> CREATE ... (END)"); + } + + void onStart(ewol::Context& _context) override { + APPL_INFO("==> START ... (BEGIN)"); + // init internal global value + audio::river::initString(configurationRiver); + + _context.setSize(vec2(800, 600)); + + // select internal data for font ... + _context.getFontDefault().setUseExternal(true); + _context.getFontDefault().setSize(19); + + appl::widget::DataViewer::createManagerWidget(_context.getWidgetManager()); + + ememory::SharedPtr basicWindows = appl::Windows::create(); + if (basicWindows == null) { + APPL_ERROR("Can not allocate the basic windows"); + _context.exit(-1); + return; + } + // create the specific windows + _context.setWindows(basicWindows); + + // 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") { + // 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 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); + } + } + } + } + } + */ + APPL_INFO("==> START ... (END)"); + return; + } + void onStop(ewol::Context& _context) override { + APPL_INFO("==> STOP ... (START)"); + APPL_INFO("==> STOP ... (END)"); + } + void onKillDemand(ewol::Context& _context) override { + APPL_INFO("==> User demand kill ... (START)"); + _context.exit(0); + APPL_INFO("==> User demand kill ... (END)"); + } +}; + +/** + * @brief Main of the program (This can be set in every case, but it is not used in Andoid...). + * @param std IO + * @return std IO + */ +int main(int _argc, const char *_argv[]) { + // second possibility + return ewol::run(ETK_NEW(MainApplication), _argc, _argv); +} \ No newline at end of file diff --git a/recoWord/appl/widget/DataViewer.cpp b/recoWord/appl/widget/DataViewer.cpp new file mode 100644 index 0000000..636b353 --- /dev/null +++ b/recoWord/appl/widget/DataViewer.cpp @@ -0,0 +1,332 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include + +static const int32_t nbSecondOffset = 3; +static const float nbSecondSilence = 1.1; +static const int32_t nbSecond = 10; +static const float nbSecondPreviousPost = 1; +static const float startThresholdLevel = 0.2; +static const float stopThresholdLevel = 0.1; + + + +appl::widget::DataViewer::DataViewer() : + m_minVal(-1.0f), + m_maxVal(1.0f), + m_sampleRate(48000) { + addObjectType("appl::widget::DataViewer"); +} + +void appl::widget::DataViewer::init() { + ewol::Widget::init(); + m_manager = audio::river::Manager::create("appl::widget::DataViewer"); + m_data.resize(m_sampleRate*nbSecond*3, 0.0); + m_data.clear(); + reset(); +} + + +appl::widget::DataViewer::~DataViewer() { + +} + + + +void appl::widget::DataViewer::onDataReceived(const void* _data, + const audio::Time& _time, + size_t _nbChunk, + enum audio::format _format, + uint32_t _frequency, + const etk::Vector& _map) { + ethread::RecursiveLock lock(m_mutex); + if (_format != audio::format_float) { + APPL_ERROR("call wrong type ... (need int16_t)"); + } + // get the curent power of the signal. + const float* data = static_cast(_data); + for (size_t iii=0; iii<_nbChunk*_map.size(); ++iii) { + m_data.pushBack(data[iii]); + if (m_startAnalyse == false) { + m_detectStartPosition = m_data.size(); + m_detectStopPosition = m_data.size() + 1; + if (data[iii] > startThresholdLevel) { + m_startAnalyse = true; + m_time = echrono::Clock::now(); + m_silenceCount = 0; + } + } else { + if (data[iii] > stopThresholdLevel) { + m_silenceCount = 0; + m_detectStopPosition = m_data.size(); + m_detectMax = etk::max(m_detectMax, etk::abs(data[iii])); + } else { + m_silenceCount++; + } + } + } +} + +void appl::widget::DataViewer::start() { + ethread::RecursiveLock lock(m_mutex); + if (m_interface == null) { + reset(); + //Get the generic input: + etk::Vector channel; + channel.pushBack(audio::channel_frontLeft); + m_interface = m_manager->createInput(m_sampleRate, + channel, + audio::format_float, + "microphone"); + if(m_interface == null) { + APPL_ERROR("null interface"); + return; + } + // set callback mode ... + m_interface->setInputCallback([&](const void* _data, + const audio::Time& _time, + size_t _nbChunk, + enum audio::format _format, + uint32_t _frequency, + const etk::Vector& _map) { + onDataReceived(_data, _time, _nbChunk, _format, _frequency, _map); + }); + // start the stream + m_interface->start(); + m_PCH = getObjectManager().periodicCall.connect(this, &appl::widget::DataViewer::periodicCall); + } +} + +void appl::widget::DataViewer::stop() { + ethread::RecursiveLock lock(m_mutex); + if (m_interface != null) { + m_interface->stop(); + m_interface.reset(); + m_PCH.disconnect(); + } +} + + +void appl::widget::DataViewer::recordToggle() { + ethread::RecursiveLock lock(m_mutex); + if (m_interface == null) { + start(); + } else { + stop(); + } +} + +void appl::widget::DataViewer::onDraw() { + m_draw.draw(); +} + + +void appl::widget::DataViewer::onRegenerateDisplay() { + //!< Check if we really need to redraw the display, if not needed, we redraw the previous data ... + if (needRedraw() == false) { + return; + } + // remove previous data + m_draw.clear(); + // set background + m_draw.setColor(etk::color::black); + m_draw.setPos(vec2(0,0)); + m_draw.rectangleWidth(m_size); + ethread::RecursiveLock lock(m_mutex); + if (m_data.size() == 0) { + return; + } + // create n section for display: + int32_t nbSlot = m_size.x(); + int32_t sizeSlot = m_size.x()/nbSlot; + etk::Vector list; + //APPL_INFO("nbSlot : " << nbSlot << " sizeSlot=" << sizeSlot << " m_size=" << m_size); + list.resize(nbSlot,0.0f); + int32_t step = m_sampleRate*nbSecond/nbSlot; + for (size_t kkk=0; kkk m_size.x()) { + APPL_ERROR("wrong display position"); + } + } + // detect sound + if (m_detectStopPosition > m_detectStartPosition) { + m_draw.setColor(etk::color::orange); + m_draw.setThickness(1); + float posStart = double(m_detectStartPosition-m_startDisplayOffset)/double(step)*sizeSlot; + float posStop = double(m_detectStopPosition-m_startDisplayOffset)/double(step)*sizeSlot; + m_draw.setPos(vec2(posStart, origin - ratioY*m_detectMax)); + //m_draw.rectangle(vec2(posStop, origin + ratioY*m_detectMax)); + //APPL_ERROR("draw position: " << posStart << " " << posStop); + + m_draw.lineTo(vec2(posStart, origin + ratioY*m_detectMax)); + m_draw.lineTo(vec2(posStop, origin + ratioY*m_detectMax)); + m_draw.lineTo(vec2(posStop, origin - ratioY*m_detectMax)); + m_draw.lineTo(vec2(posStart, origin - ratioY*m_detectMax)); + } + // sound recorded + if (m_detectStopPosition > m_detectStartPosition) { + m_draw.setColor(etk::color::blue); + m_draw.setThickness(1); + float posStart = double(m_detectStartPosition-m_startDisplayOffset-nbSecondPreviousPost*m_sampleRate)/double(step)*sizeSlot; + float posStop = double(m_detectStopPosition-m_startDisplayOffset+nbSecondPreviousPost*m_sampleRate)/double(step)*sizeSlot; + m_draw.setPos(vec2(posStart, origin - ratioY*0.5)); + m_draw.lineTo(vec2(posStart, origin + ratioY*0.5)); + m_draw.lineTo(vec2(posStop, origin + ratioY*0.5)); + m_draw.lineTo(vec2(posStop, origin - ratioY*0.5)); + m_draw.lineTo(vec2(posStart, origin - ratioY*0.5)); + } + // End of silence detection + if (m_detectStopPosition > m_detectStartPosition) { + m_draw.setColor(etk::color::red); + m_draw.setThickness(1); + float pos = double(m_detectStopPosition-m_startDisplayOffset+nbSecondSilence*m_sampleRate)/double(step)*sizeSlot; + m_draw.setPos(vec2(pos, origin - ratioY*0.5)); + m_draw.lineTo(vec2(pos, origin + ratioY*0.5)); + } + if (m_detectStopPosition <= m_detectStartPosition) { + m_draw.setColor(etk::color::red); + m_draw.setThickness(1); + // start threshold + m_draw.setPos(vec2(0, origin - ratioY*startThresholdLevel)); + m_draw.lineTo(vec2(m_size.x(), origin - ratioY*startThresholdLevel)); + m_draw.setPos(vec2(0, origin + ratioY*startThresholdLevel)); + m_draw.lineTo(vec2(m_size.x(), origin + ratioY*startThresholdLevel)); + } else { + m_draw.setColor(etk::color::red); + m_draw.setThickness(1); + float posStop = double(m_detectStopPosition-m_startDisplayOffset)/double(step)*sizeSlot; + // start threshold + m_draw.setPos(vec2(0, origin - ratioY*startThresholdLevel)); + m_draw.lineTo(vec2(posStop, origin - ratioY*startThresholdLevel)); + m_draw.setPos(vec2(0, origin + ratioY*startThresholdLevel)); + m_draw.lineTo(vec2(posStop, origin + ratioY*startThresholdLevel)); + + // stop threshold + m_draw.setPos(vec2(posStop, origin - ratioY*stopThresholdLevel)); + m_draw.lineTo(vec2(m_size.x(), origin - ratioY*stopThresholdLevel)); + m_draw.setPos(vec2(posStop, origin + ratioY*stopThresholdLevel)); + m_draw.lineTo(vec2(m_size.x(), origin + ratioY*stopThresholdLevel)); + } +} + + + + +void appl::widget::DataViewer::periodicCall(const ewol::event::Time& _event) { + ethread::RecursiveLock lock(m_mutex); + int32_t nbSampleDelta = _event.getDeltaCall() * float(m_sampleRate); + if (m_startAnalyse == false) { + if (m_data.size() > m_sampleRate*nbSecondOffset) { + m_startDisplayOffset = m_data.size() - m_sampleRate*nbSecondOffset; + } + } else { + if (m_silenceCount > m_sampleRate*nbSecondSilence) { + stop(); + signalFinished.emit(); + } + } + markToRedraw(); +} + + +void appl::widget::DataViewer::reset() { + ethread::RecursiveLock lock(m_mutex); + m_data.clear(); + m_startDisplayOffset = 0; + m_startAnalyse = false; + m_silenceCount = 0; + m_detectStartPosition = 0; + m_detectStopPosition = 0; + m_detectMax = 0; + m_data.resize(m_sampleRate*nbSecondOffset, 0.0); +} + + + +bool appl::widget::DataViewer::onEventInput(const ewol::event::Input& _event) { + APPL_INFO("event XXX " << _event); + vec2 relativePos = relativePosition(_event.getPos()); + if ( _event.getType() == gale::key::type::mouse + && _event.getId() == 4 + && _event.getStatus() == gale::key::status::down) { + m_startDisplayOffset += m_sampleRate * 0.25; + if(m_startDisplayOffset >= m_data.size()-m_sampleRate*nbSecondOffset) { + m_startDisplayOffset = m_data.size()- m_sampleRate*nbSecondOffset; + } + markToRedraw(); + return true; + } else if ( _event.getType() == gale::key::type::mouse + && _event.getId() == 5 + && _event.getStatus() == gale::key::status::down) { + m_startDisplayOffset -= m_sampleRate * 0.25; + if(m_startDisplayOffset<0) { + m_startDisplayOffset = 0; + } + markToRedraw(); + return true; + } + return false; +} + + +void appl::widget::DataViewer::store(const etk::String& _userName, const etk::String& _value, const etk::String& _language) { + if (m_data.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)); + doc.add("value", ejson::String(_value)); + doc.add("language", ejson::String(_language)); + doc.add("time", ejson::Number(m_time.get())); + doc.add("audio_format", ejson::String("float")); + doc.add("audio_channel", ejson::Number(1)); + doc.add("audio_sample_rate", ejson::Number(48000)); + doc.add("audio_filename", ejson::String(baseName + ".raw")); + + + 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"; + + 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 fileIO = etk::uri::get(fileNameAudioFile); + if (fileIO->open(etk::io::OpenMode::Write) == false) { + return; + } + fileIO->write(&m_data[posStart], 1*audio::getFormatBytes(audio::format_float), (posStop-posStart)); + fileIO->close(); + } + APPL_WARNING("store: " << fileNameAudioFile); +} \ No newline at end of file diff --git a/recoWord/appl/widget/DataViewer.hpp b/recoWord/appl/widget/DataViewer.hpp new file mode 100644 index 0000000..0a04d33 --- /dev/null +++ b/recoWord/appl/widget/DataViewer.hpp @@ -0,0 +1,73 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include