File indexing completed on 2024-05-12 03:52:13

0001 /****************************************************************************
0002 **
0003 ** Copyright (C) 2016 by Sandro S. Andrade <sandroandrade@kde.org>
0004 **
0005 ** This program is free software; you can redistribute it and/or
0006 ** modify it under the terms of the GNU General Public License as
0007 ** published by the Free Software Foundation; either version 2 of
0008 ** the License or (at your option) version 3 or any later version
0009 ** accepted by the membership of KDE e.V. (or its successor approved
0010 ** by the membership of KDE e.V.), which shall act as a proxy
0011 ** defined in Section 14 of version 3 of the license.
0012 **
0013 ** This program is distributed in the hope that it will be useful,
0014 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
0015 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0016 ** GNU General Public License for more details.
0017 **
0018 ** You should have received a copy of the GNU General Public License
0019 ** along with this program.  If not, see <http://www.gnu.org/licenses/>.
0020 **
0021 ****************************************************************************/
0022 
0023 #include "csoundsoundcontroller.h"
0024 #include "csengine.h"
0025 
0026 #include <QLoggingCategory>
0027 #include <QtMath>
0028 #include <QtQml>
0029 
0030 Q_DECLARE_LOGGING_CATEGORY(MINUETANDROID)
0031 
0032 CsoundSoundController::CsoundSoundController(QObject *parent)
0033     : Minuet::ISoundController(parent), m_csoundEngine(new CsEngine)
0034 {
0035     qmlRegisterType<CsoundSoundController>("org.kde.minuet", 1, 0, "CsoundSoundController");
0036     openExerciseFile();
0037     //    setQuestionLabel("new question");
0038 }
0039 
0040 void CsoundSoundController::openExerciseFile()
0041 {
0042     QStringList templateList;
0043     templateList.append(QStringLiteral("assets:/share/template.csd"));
0044     //    templateList.append(QStringLiteral("assets:/share/template_rhythm.csd"));
0045 
0046     qDebug() << "DIRPATH: " << QCoreApplication::applicationDirPath();
0047     qDebug() << "ASSETSPATH: " << QDir("assets:/").canonicalPath();
0048     qDebug() << "QStandardPaths::ApplicationsLocation: "
0049              << QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);
0050     qDebug() << "QStandardPaths::GenericDataLocation: "
0051              << QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
0052     qDebug() << "QStandardPaths::AppDataLocation: "
0053              << QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
0054     qDebug() << "QStandardPaths::AppLocalDataLocation: "
0055              << QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation);
0056     qDebug() << "QStandardPaths::AppConfigLocation: "
0057              << QStandardPaths::standardLocations(QStandardPaths::AppConfigLocation);
0058     QDir appDir(QCoreApplication::applicationDirPath());
0059     qDebug() << "Contains libfluidOpcodes.so? "
0060              << appDir.entryList(QDir::Files).contains("libfluidOpcodes.so");
0061     qDebug() << "DIRPATH: " << appDir << " Contents: " << appDir.entryList(QDir::AllEntries);
0062     appDir.cdUp();
0063     qDebug() << "DIRPATH: " << appDir << " Contents: " << appDir.entryList(QDir::AllEntries);
0064     appDir.cdUp();
0065     qDebug() << "DIRPATH: " << appDir << " Contents: " << appDir.entryList(QDir::AllEntries);
0066     QDir reserved("/data/data/org.kde.minuet/qt-reserved-files/");
0067     qDebug() << "RESERVED: " << reserved << " Contents: " << reserved.entryList(QDir::AllEntries);
0068 
0069     QDirIterator it("/", QDirIterator::Subdirectories);
0070     while (it.hasNext()) {
0071         qDebug() << "FILE: " << it.next();
0072     }
0073     foreach (const QString &templateString, templateList) {
0074         QFile sfile(templateString);
0075         if (!sfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
0076             return;
0077         }
0078 
0079         QTextStream in(&sfile);
0080         QString lineData;
0081         QString tempBeginLine;
0082         QString tempEndLine;
0083 
0084         while (!in.atEnd()) {
0085             lineData = in.readLine();
0086             lineData.replace("APPDIRPATH", QCoreApplication::applicationDirPath());
0087             tempBeginLine = tempBeginLine + lineData + '\n';
0088             if (lineData.contains("<CsScore>")) {
0089                 m_begLine.append(tempBeginLine);
0090                 break;
0091             }
0092         }
0093 
0094         while (!in.atEnd()) {
0095             lineData = in.readLine();
0096             tempEndLine += lineData + '\n';
0097         }
0098         m_endLine.append(tempEndLine);
0099     }
0100     qDebug() << "m_begLine: " << m_begLine;
0101     qDebug() << "m_endLine: " << m_endLine;
0102 }
0103 
0104 void CsoundSoundController::appendEvent(QList<unsigned int> midiNotes, QList<float> barStartInfo,
0105                                         QString playMode)
0106 {
0107     // TODO : use grantlee processing or any other text template library
0108     int templateNumber = playMode == "rhythm" ? 1 : 0;
0109     QString content;
0110     QString fifthParam = QStringLiteral("100");
0111     QFile m_csdFileOpen(QStringLiteral("./template.csd"));
0112 
0113     qDebug() << "CREATING " << QDir::currentPath() + "/template.csd";
0114     if (!m_csdFileOpen.isOpen()) {
0115         m_csdFileOpen.open(QIODevice::ReadWrite | QIODevice::Text);
0116     }
0117     m_csdFileOpen.resize(0);
0118 
0119     if (playMode == "rhythm") {
0120         QString wave = QStringLiteral("f 1 0 16384 10 1\n\n");
0121         content += wave;
0122         fifthParam = QStringLiteral("");
0123     }
0124 
0125     for (int i = 0; i < midiNotes.count(); i++) {
0126         QString initScore = QString("i 1 %1 %2 %3 %4\n")
0127                                 .arg(QString::number(barStartInfo.at(i)))
0128                                 .arg(QString::number(1))
0129                                 .arg(QString::number(midiNotes.at(i)))
0130                                 .arg(fifthParam);
0131         //        content += initScore;
0132     }
0133 
0134     if (playMode != "rhythm") {
0135         QString instrInit
0136             = "i 99 0 " + QString::number(barStartInfo.at(barStartInfo.count() - 1) + 1)
0137               + "\ne\n";  // instrument will be active till the end of the notes +1 second
0138         //        content += instrInit;
0139     }
0140 
0141     QString templateContent = m_begLine[templateNumber] + content + m_endLine[templateNumber];
0142     m_csdFileOpen.seek(0);
0143     QByteArray contentByte = templateContent.toUtf8();
0144     m_csdFileOpen.write(contentByte);
0145 }
0146 
0147 CsoundSoundController::~CsoundSoundController()
0148 {
0149     delete m_csoundEngine;
0150 }
0151 
0152 void CsoundSoundController::prepareFromExerciseOptions(QJsonArray selectedExerciseOptions)
0153 {
0154     float barStart = 0;
0155     QList<unsigned int> midiNotes;
0156     QList<float> barStartInfo;
0157 
0158     if (m_playMode == "rhythm") {
0159         for (int k = 0; k < 4; ++k) {
0160             midiNotes.append(80);
0161             barStartInfo.append(barStart++);
0162         }
0163     }
0164 
0165     int exerciseOptionsSize = selectedExerciseOptions.size();
0166     for (int i = 0; i < exerciseOptionsSize; ++i) {
0167         QString sequence
0168             = selectedExerciseOptions[i].toObject()[QStringLiteral("sequence")].toString();
0169 
0170         unsigned int chosenRootNote
0171             = selectedExerciseOptions[i].toObject()[QStringLiteral("rootNote")].toString().toInt();
0172         if (m_playMode != "rhythm") {
0173             midiNotes.append(chosenRootNote);
0174             barStartInfo.append(barStart);
0175 
0176             unsigned int j = 1;
0177             foreach (const QString &additionalNote, sequence.split(' ')) {
0178                 midiNotes.append(chosenRootNote + additionalNote.toInt());
0179                 barStartInfo.append((m_playMode == "scale") ? barStart + j : barStart);
0180                 ++j;
0181             }
0182             barStart++;
0183         } else {
0184             midiNotes.append(80);
0185             barStartInfo.append(barStart);
0186             foreach (QString additionalNote, sequence.split(' ')) {  // krazy:exclude=foreach
0187                 midiNotes.append(37);
0188                 barStartInfo.append(barStart);
0189                 float dotted = 1;
0190                 if (additionalNote.endsWith('.')) {
0191                     dotted = 1.5;
0192                     additionalNote.chop(1);
0193                 }
0194                 barStart += dotted * 1 * (4.0 / additionalNote.toInt());
0195             }
0196         }
0197     }
0198 
0199     if (m_playMode == "rhythm") {
0200         midiNotes.append(80);
0201         barStartInfo.append(barStart);
0202     }
0203     appendEvent(midiNotes, barStartInfo, m_playMode);
0204 }
0205 
0206 void CsoundSoundController::prepareFromMidiFile(const QString &fileName)
0207 {
0208     Q_UNUSED(fileName)
0209 }
0210 
0211 void CsoundSoundController::play()
0212 {
0213     m_csoundEngine->start();
0214     setState(PlayingState);
0215 }
0216 
0217 void CsoundSoundController::pause() {}
0218 
0219 void CsoundSoundController::stop()
0220 {
0221     m_csoundEngine->stop();
0222     setState(StoppedState);
0223 }
0224 
0225 void CsoundSoundController::reset() {}
0226 
0227 void CsoundSoundController::setPitch(qint8 pitch)
0228 {
0229     Q_UNUSED(pitch)
0230 }
0231 
0232 void CsoundSoundController::setVolume(quint8 volume)
0233 {
0234     Q_UNUSED(volume)
0235 }
0236 
0237 void CsoundSoundController::setTempo(quint8 tempo)
0238 {
0239     Q_UNUSED(tempo)
0240 }
0241 
0242 //#include "moc_csoundsoundcontroller.cpp"