Mercurial > hg > qm-vamp-plugins
changeset 21:d695fc2baa91
* Turning key-mode plugin into a generic key detection plugin, and attempting to
debug it
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Mon, 22 Jan 2007 17:32:40 +0000 |
parents | 1f1881046b0c |
children | 6d014fb538db |
files | libmain.cpp plugins/BeatDetect.cpp plugins/GetModePlugin.cpp plugins/GetModePlugin.h plugins/KeyDetect.cpp plugins/KeyDetect.h qm-vamp-plugins.cat qm-vamp-plugins.pro |
diffstat | 8 files changed, 452 insertions(+), 289 deletions(-) [+] |
line wrap: on
line diff
--- a/libmain.cpp Tue Dec 12 10:34:53 2006 +0000 +++ b/libmain.cpp Mon Jan 22 17:32:40 2007 +0000 @@ -14,13 +14,13 @@ #include "plugins/ChromagramPlugin.h" #include "plugins/ConstantQSpectrogram.h" #include "plugins/TonalChangeDetect.h" -#include "plugins/GetModePlugin.h" +#include "plugins/KeyDetect.h" static Vamp::PluginAdapter<BeatDetector> beatDetectorAdapter; static Vamp::PluginAdapter<ChromagramPlugin> chromagramPluginAdapter; static Vamp::PluginAdapter<ConstantQSpectrogram> constantQAdapter; static Vamp::PluginAdapter<TonalChangeDetect> tonalChangeDetectorAdapter; -static Vamp::PluginAdapter<GetModePlugin> keyModeAdapter; +static Vamp::PluginAdapter<KeyDetector> keyDetectorAdapter; const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int index) { @@ -29,7 +29,7 @@ case 1: return chromagramPluginAdapter.getDescriptor(); case 2: return constantQAdapter.getDescriptor(); case 3: return tonalChangeDetectorAdapter.getDescriptor(); - case 4: return keyModeAdapter.getDescriptor(); + case 4: return keyDetectorAdapter.getDescriptor(); default: return 0; } }
--- a/plugins/BeatDetect.cpp Tue Dec 12 10:34:53 2006 +0000 +++ b/plugins/BeatDetect.cpp Mon Jan 22 17:32:40 2007 +0000 @@ -61,7 +61,7 @@ string BeatDetector::getDescription() const { - return "Tempo Tracker"; + return "Beat Tracker"; } string
--- a/plugins/GetModePlugin.cpp Tue Dec 12 10:34:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#include "GetModePlugin.h" - -using std::string; -using std::vector; -//using std::cerr; -using std::endl; - -#include <cmath> - - -GetModePlugin::GetModePlugin(float inputSampleRate) : - Plugin(inputSampleRate), - m_stepSize(0), - m_blockSize(32768), - m_GetMode(0), - m_InputFrame(0), - m_BlockandHopSize(0) -{ - m_BlockandHopSize= 32768; -} - -GetModePlugin::~GetModePlugin() -{ - if( m_GetMode ) - { - delete m_GetMode; - m_GetMode = 0; - } - - if( m_InputFrame ) - { - delete [] m_InputFrame; - m_InputFrame = 0; - } -} - -string -GetModePlugin::getName() const -{ - return "qm-keymode"; -} - -string -GetModePlugin::getDescription() const -{ - return "Key Mode"; -} - -string -GetModePlugin::getMaker() const -{ - return "Katy Noland and Christian Landone"; -} - -int -GetModePlugin::getPluginVersion() const -{ - return 2; -} - -string -GetModePlugin::getCopyright() const -{ - return "Centre for Digital Music QMUL"; -} - -bool -GetModePlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - if (channels < getMinChannelCount() || - channels > getMaxChannelCount()) return false; - - m_stepSize = stepSize; - m_blockSize = blockSize; - - if( stepSize != m_BlockandHopSize || blockSize != m_BlockandHopSize ) - return false; - - m_GetMode = new GetKeyMode( 10, 10 ); - - m_InputFrame = new double[m_BlockandHopSize]; - - return true; -} - -void -GetModePlugin::reset() -{ - for( unsigned int i = 0; i < m_BlockandHopSize; i++ ) - { - m_InputFrame[ i ] = 0.0; - } -} - - -GetModePlugin::OutputList -GetModePlugin::getOutputDescriptors() const -{ - OutputList list; - - OutputDescriptor d; - d.name = "mode"; - d.unit = ""; - d.description = "Key Mode"; - d.hasFixedBinCount = true; - d.binCount = 1; - d.hasKnownExtents = true; - d.isQuantized = true; - d.minValue = 0; - d.maxValue = 1; - d.quantizeStep = 1; - d.binNames.push_back("Major = 0, Minor = 1"); - d.sampleType = OutputDescriptor::OneSamplePerStep; - list.push_back(d); - - return list; -} - -GetModePlugin::FeatureSet -GetModePlugin::process(const float *const *inputBuffers, - Vamp::RealTime) -{ - if (m_stepSize == 0) { - return FeatureSet(); - } - - FeatureSet returnFeatures; - - for( unsigned int i = 0 ; i < m_BlockandHopSize; i++ ) - { - m_InputFrame[i] = (double)inputBuffers[0][i]; - } - - - int minor = m_GetMode->isModeMinor(m_GetMode->process( m_InputFrame )); - - Feature feature; - feature.hasTimestamp = false; - - feature.values.push_back((float)minor); - returnFeatures[0].push_back(feature); - feature.values.clear(); - - return returnFeatures; -} - -GetModePlugin::FeatureSet -GetModePlugin::getRemainingFeatures() -{ - return FeatureSet(); -} - - -size_t -GetModePlugin::getPreferredStepSize() const -{ - return 0; -} - -size_t -GetModePlugin::getPreferredBlockSize() const -{ - return 32768; -} -
--- a/plugins/GetModePlugin.h Tue Dec 12 10:34:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#ifndef _GETMODE_PLUGIN_H_ -#define _GETMODE_PLUGIN_H_ - -#include <vamp-sdk/Plugin.h> - -#include <dsp/keydetection/GetKeyMode.h> - -class GetModePlugin : public Vamp::Plugin -{ -public: - GetModePlugin(float inputSampleRate); - virtual ~GetModePlugin(); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - void reset(); - - InputDomain getInputDomain() const { return TimeDomain; } - - std::string getName() const; - std::string getDescription() const; - std::string getMaker() const; - int getPluginVersion() const; - std::string getCopyright() const; - - OutputList getOutputDescriptors() const; - - FeatureSet process(const float *const *inputBuffers, - Vamp::RealTime timestamp); - - FeatureSet getRemainingFeatures(); - - size_t getPreferredStepSize() const; - size_t getPreferredBlockSize() const; - -protected: - size_t m_stepSize; - size_t m_blockSize; - - GetKeyMode* m_GetMode; - double* m_InputFrame; - unsigned int m_BlockandHopSize; -}; - - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/KeyDetect.cpp Mon Jan 22 17:32:40 2007 +0000 @@ -0,0 +1,356 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006-2007 QMUL. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "KeyDetect.h" + +using std::string; +using std::vector; +//using std::cerr; +using std::endl; + +#include <cmath> + + +KeyDetector::KeyDetector(float inputSampleRate) : + Plugin(inputSampleRate), + m_stepSize(0), + m_blockSize(0), + m_tuningFrequency(440), + m_length(10), + m_getKeyMode(0), + m_inputFrame(0), + m_prevKey(-1) +{ +} + +KeyDetector::~KeyDetector() +{ + delete m_getKeyMode; + if ( m_inputFrame ) { + delete [] m_inputFrame; + } +} + +string +KeyDetector::getName() const +{ + return "qm-keydetector"; +} + +string +KeyDetector::getDescription() const +{ + return "Key Detector"; +} + +string +KeyDetector::getMaker() const +{ + return "Katy Noland and Christian Landone, Queen Mary, University of London"; +} + +int +KeyDetector::getPluginVersion() const +{ + return 2; +} + +string +KeyDetector::getCopyright() const +{ + return "Copyright (c) 2006-2007 - All Rights Reserved"; +} + +KeyDetector::ParameterList +KeyDetector::getParameterDescriptors() const +{ + ParameterList list; + + ParameterDescriptor desc; + desc.name = "tuning"; + desc.description = "Tuning Frequency"; + desc.unit = "Hz"; + desc.minValue = 420; + desc.maxValue = 460; + desc.defaultValue = 440; + desc.isQuantized = false; + list.push_back(desc); + + desc.name = "length"; + desc.description = "Window Length"; + desc.unit = "chroma frames"; + desc.minValue = 1; + desc.maxValue = 30; + desc.defaultValue = 10; + desc.isQuantized = true; + desc.quantizeStep = 1; + list.push_back(desc); + + return list; +} + +float +KeyDetector::getParameter(std::string param) const +{ + if (param == "tuning") { + return m_tuningFrequency; + } + if (param == "length") { + return m_length; + } + std::cerr << "WARNING: KeyDetect::getParameter: unknown parameter \"" + << param << "\"" << std::endl; + return 0.0; +} + +void +KeyDetector::setParameter(std::string param, float value) +{ + if (param == "tuning") { + m_tuningFrequency = value; + } else if (param == "length") { + m_length = int(value + 0.1); + } else { + std::cerr << "WARNING: KeyDetect::setParameter: unknown parameter \"" + << param << "\"" << std::endl; + } +} + +bool +KeyDetector::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (m_getKeyMode) { + delete m_getKeyMode; + m_getKeyMode = 0; + } + + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_getKeyMode = new GetKeyMode(int(m_inputSampleRate + 0.1), + m_tuningFrequency, + m_length, m_length); + + m_stepSize = m_getKeyMode->getHopSize(); + m_blockSize = m_getKeyMode->getBlockSize(); + + if (stepSize != m_stepSize || blockSize != m_blockSize) { + std::cerr << "KeyDetector::initialise: step/block sizes " + << stepSize << "/" << blockSize << " differ from required " + << m_stepSize << "/" << m_blockSize << std::endl; + delete m_getKeyMode; + m_getKeyMode = 0; + return false; + } + + m_inputFrame = new double[m_blockSize]; + + m_prevKey = -1; + + return true; +} + +void +KeyDetector::reset() +{ + if (m_getKeyMode) { + delete m_getKeyMode; + m_getKeyMode = new GetKeyMode(int(m_inputSampleRate + 0.1), + m_tuningFrequency, + m_length, m_length); + } + + if (m_inputFrame) { + for( unsigned int i = 0; i < m_blockSize; i++ ) { + m_inputFrame[ i ] = 0.0; + } + } + + m_prevKey = -1; +} + + +KeyDetector::OutputList +KeyDetector::getOutputDescriptors() const +{ + OutputList list; + + OutputDescriptor d; + d.name = "tonic"; + d.unit = ""; + d.description = "Tonic Pitch"; + d.hasFixedBinCount = true; + d.binCount = 1; + d.hasKnownExtents = true; + d.isQuantized = true; + d.minValue = 0; + d.maxValue = 11; + d.quantizeStep = 1; + d.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(d); + + d.name = "mode"; + d.unit = ""; + d.description = "Key Mode"; + d.hasFixedBinCount = true; + d.binCount = 1; + d.hasKnownExtents = true; + d.isQuantized = true; + d.minValue = 0; + d.maxValue = 1; + d.quantizeStep = 1; + d.binNames.push_back("Major = 0, Minor = 1"); + d.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(d); + + d.name = "key"; + d.unit = ""; + d.description = "Key"; + d.hasFixedBinCount = true; + d.binCount = 1; + d.hasKnownExtents = true; + d.isQuantized = true; + d.minValue = 0; + d.maxValue = 23; + d.quantizeStep = 1; + d.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(d); + + return list; +} + +KeyDetector::FeatureSet +KeyDetector::process(const float *const *inputBuffers, + Vamp::RealTime now) +{ + if (m_stepSize == 0) { + return FeatureSet(); + } + + FeatureSet returnFeatures; + + for ( unsigned int i = 0 ; i < m_blockSize; i++ ) { + m_inputFrame[i] = (double)inputBuffers[0][i]; + } + +// int key = (m_getKeyMode->process(m_inputFrame) % 24); + int key = m_getKeyMode->process(m_inputFrame); + int minor = m_getKeyMode->isModeMinor(key); + int tonic = key; + if (tonic > 12) tonic -= 12; + + int prevTonic = m_prevKey; + if (prevTonic > 12) prevTonic -= 12; + + if (tonic != prevTonic) { + Feature feature; + feature.hasTimestamp = false; +// feature.timestamp = now; + feature.values.push_back((float)tonic); + feature.label = getKeyName(tonic); + returnFeatures[0].push_back(feature); // tonic + } + + if (minor != (m_getKeyMode->isModeMinor(m_prevKey))) { + Feature feature; + feature.hasTimestamp = false; + feature.values.push_back((float)minor); + feature.label = (minor ? "Minor" : "Major"); + returnFeatures[1].push_back(feature); // mode + } + + if (key != m_prevKey) { + Feature feature; +// feature.hasTimestamp = true; + feature.hasTimestamp = false; +// feature.timestamp = now; + feature.values.push_back((float)key); + feature.label = std::string(getKeyName(tonic)); + if (minor) feature.label += " minor"; + else feature.label += " major"; + returnFeatures[2].push_back(feature); // key + } + + m_prevKey = key; + + return returnFeatures; +} + +KeyDetector::FeatureSet +KeyDetector::getRemainingFeatures() +{ + return FeatureSet(); +} + + +size_t +KeyDetector::getPreferredStepSize() const +{ + if (!m_stepSize) { + GetKeyMode gkm(int(m_inputSampleRate + 0.1), + m_tuningFrequency, m_length, m_length); + m_stepSize = gkm.getHopSize(); + m_blockSize = gkm.getBlockSize(); + } + return m_stepSize; +} + +size_t +KeyDetector::getPreferredBlockSize() const +{ + if (!m_blockSize) { + GetKeyMode gkm(int(m_inputSampleRate + 0.1), + m_tuningFrequency, m_length, m_length); + m_stepSize = gkm.getHopSize(); + m_blockSize = gkm.getBlockSize(); + } + return m_blockSize; +} + +const char * +KeyDetector::getKeyName(int index) +{ + static const char *names[] = { + "C", "C# / Db", "D", "D# / Eb", + "E", "F", "F# / Gb", "G", + "G# / Ab", "A", "A# / Bb", "B" + }; + if (index < 1 || index > 12) { + return "(unknown)"; + } + return names[index - 1]; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/KeyDetect.h Mon Jan 22 17:32:40 2007 +0000 @@ -0,0 +1,89 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006-2007 QMUL. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef _GETMODE_PLUGIN_H_ +#define _GETMODE_PLUGIN_H_ + +#include <vamp-sdk/Plugin.h> + +#include <dsp/keydetection/GetKeyMode.h> + +class KeyDetector : public Vamp::Plugin +{ +public: + KeyDetector(float inputSampleRate); + virtual ~KeyDetector(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + void reset(); + + InputDomain getInputDomain() const { return TimeDomain; } + + std::string getName() const; + std::string getDescription() const; + std::string getMaker() const; + int getPluginVersion() const; + std::string getCopyright() const; + + ParameterList getParameterDescriptors() const; + float getParameter(std::string) const; + void setParameter(std::string, float); + + OutputList getOutputDescriptors() const; + + FeatureSet process(const float *const *inputBuffers, + Vamp::RealTime timestamp); + + FeatureSet getRemainingFeatures(); + + size_t getPreferredStepSize() const; + size_t getPreferredBlockSize() const; + +protected: + mutable size_t m_stepSize; + mutable size_t m_blockSize; + float m_tuningFrequency; + int m_length; + + const char *getKeyName(int index); + + GetKeyMode* m_getKeyMode; + double* m_inputFrame; + int m_prevKey; +}; + + +#endif
--- a/qm-vamp-plugins.cat Tue Dec 12 10:34:53 2006 +0000 +++ b/qm-vamp-plugins.cat Mon Jan 22 17:32:40 2007 +0000 @@ -2,4 +2,4 @@ vamp:qm-vamp-plugins:qm-chromagram::Visualisation vamp:qm-vamp-plugins:qm-constantq::Visualisation vamp:qm-vamp-plugins:qm-tonalchange::Key and Tonality -vamp:qm-vamp-plugins:qm-keymode::Key and Tonality +vamp:qm-vamp-plugins:qm-keydetector::Key and Tonality
--- a/qm-vamp-plugins.pro Tue Dec 12 10:34:53 2006 +0000 +++ b/qm-vamp-plugins.pro Mon Jan 22 17:32:40 2007 +0000 @@ -21,11 +21,11 @@ HEADERS += plugins/BeatDetect.h \ plugins/ChromagramPlugin.h \ plugins/ConstantQSpectrogram.h \ - plugins/GetModePlugin.h \ + plugins/KeyDetect.h \ plugins/TonalChangeDetect.h SOURCES += plugins/BeatDetect.cpp \ plugins/ChromagramPlugin.cpp \ plugins/ConstantQSpectrogram.cpp \ - plugins/GetModePlugin.cpp \ + plugins/KeyDetect.cpp \ plugins/TonalChangeDetect.cpp \ ./libmain.cpp