Just Intonation  Version 1.3.0 (18)
Explore scale-independent dynamically adapting tuning in just intonation
voice.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright 2016-2017 Karolin Stange, Christoph Wick, and Haye Hinrichsen
3  *
4  * This file is part of JustIntonation.
5  *
6  * JustIntonation is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * JustIntonation is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with JustIntonation. If not, see http://www.gnu.org/licenses/.
18  *****************************************************************************/
19 
20 //============================================================================
21 // Voice - a collection of scales, the acoustic static data of an instrument
22 //============================================================================
23 
24 #include "voice.h"
25 
26 #include <QDebug>
27 #include <QThread>
28 
29 #include "instrumentfilehandler.h"
30 
31 #define STATUS if (mVerbosity >= 4) qDebug() << "Voice:"
32 #define MESSAGE if (mVerbosity >= 3) qDebug() << "Voice:"
33 #define WARNING if (mVerbosity >= 2) qWarning() <<"Voice: WARNING:"
34 #define ERROR if (mVerbosity >= 1) qCritical() << "Voice: ERROR:"
35 
36 int Voice::mVerbosity = 2;
37 
38 //-----------------------------------------------------------------------------
39 // Constructor
40 //-----------------------------------------------------------------------------
44 
46  : mSampleRate(0)
47  , mHighestDampedKey(0)
48  , mDynamicVolume(true)
49  , mScales()
50  , mRecordedPitchInCents(128,0)
51 {}
52 
53 
54 //-----------------------------------------------------------------------------
55 // Compute artificial tones in standard ET
56 //-----------------------------------------------------------------------------
57 
58 void Voice::generateArtificialSound (int samplerate)
59 {
60  mScales.clear(); // Clear existing sound
61  mSampleRate = samplerate;
63  mDynamicVolume = true;
64  emit setProgressText(tr("Please wait..."));
65  mScales.resize(1); // construct only one scale
66  mScales[0].generateArtificialSound(this,samplerate);
68 }
69 
70 
71 
72 //-----------------------------------------------------------------------------
73 // Write complete data to device
74 //-----------------------------------------------------------------------------
75 
76 bool Voice::write(QIODevice &iodevice)
77 {
78  if (mScales.size()==0)
79  {
80  ERROR << "Voice::write: saving empty file.";
81  return true;
82  }
83  if (mScales.size() > 128)
84  {
85  ERROR << "Voice::write: More than 128 scales.";
86  return true;
87  }
88  if (iodevice.isOpen()) iodevice.close();
89  if (not iodevice.open(QIODevice::WriteOnly))
90  {
91  WARNING << "Voice::read: Could not open device";
92  return false;
93  }
94  char tag[16]="justintonation ";
95  iodevice.write(tag,15);
96  InstrumentFileHandler::write(iodevice,mScales.size());
100 
101  for (auto &scale : mScales)
102  {
103  if (not scale.write(iodevice,this)) return false;
104  }
105  for (auto &entry : mRecordedPitchInCents)
106  InstrumentFileHandler::write(iodevice,entry);
107  char endtag[14]=" end of file ";
108  iodevice.write(endtag,13);
109  return true;
110 }
111 
112 
113 //-----------------------------------------------------------------------------
114 // Read complete data from device
115 //-----------------------------------------------------------------------------
116 
117 bool Voice::read(QIODevice &iodevice)
118 {
119  mScales.clear();
120  if (iodevice.isOpen()) iodevice.close();
121  if (not iodevice.open(QIODevice::ReadOnly))
122  {
123  WARNING << "read: Could not open device";
124  return false;
125  }
126  QByteArray tag = iodevice.read(15);
127  if (tag.size() != 15 or strncmp(tag.data(),"justintonation ",11)!=0)
128  {
129  WARNING << "read: Invalid voice tag at the beginning";
130  return false;
131  }
132  int numberOfScales=0;
133  InstrumentFileHandler::read(iodevice,numberOfScales);
134  if (numberOfScales<0 or numberOfScales>255)
135  {
136  WARNING << "read: Unreasonable number of scales";
137  return false;
138  }
139  mScales.clear();
140  mScales.resize(numberOfScales);
141  MESSAGE << "read: Now reading" << mScales.size() << "scales.";
142 
146 
147  for (int scaleNumber=0; scaleNumber<mScales.size(); ++scaleNumber)
148  {
149  QString progress = tr("Reading scale") + " " + QString::number(scaleNumber+1)
150  + "/" + QString::number(mScales.size());
151  emit setProgressText(progress);
152  if (not mScales[scaleNumber].read(iodevice,this)) return false;
153  if (QThread::currentThread()->isInterruptionRequested()) return false;
154  }
155  STATUS << "Reading pitch corrections";
156  mRecordedPitchInCents.resize(128);
157  for (auto &entry : mRecordedPitchInCents)
158  InstrumentFileHandler::read(iodevice,entry);
159 
160  QByteArray endtag = iodevice.read(13);
161  if (endtag.size() != 13 or strncmp(endtag.data()," end of file ",13)!=0)
162  {
163  WARNING << "Voice::read: Invalid voice tag and the end of file";
164  return false;
165  }
166  MESSAGE << "Voice::read: we have read" << mScales.size() << "scales.";
167  return true;
168 }
169 
170 
171 
173 {
174  for (Scale &scale : mScales) scale.cancel();
175 }
176 
177 
178 //-----------------------------------------------------------------------------
179 // Clear all data
180 //-----------------------------------------------------------------------------
181 
183 {
184  MESSAGE << "Voice::Clear: Clearing all scales";
185  mScales.clear();
186 }
187 
188 
189 //-----------------------------------------------------------------------------
190 // print information about this voice
191 //-----------------------------------------------------------------------------
192 
194 {
195  qDebug() << "Voice containing" << mScales.size() << "scales";
196  for (auto &e : mScales) e.printInfo();
197 }
198 
void cancel()
Definition: voice.cpp:172
int mHighestDampedKey
Definition: voice.h:76
void generateArtificialSound(int samplerate)
Definition: voice.cpp:58
bool mDynamicVolume
Definition: voice.h:77
#define WARNING
Definition: voice.cpp:33
void setProgressText(QVariant text)
static int mVerbosity
Verbosity of qDebug() message.
Definition: voice.h:67
bool write(QIODevice &iodevice)
Definition: voice.cpp:76
Scale - a set of PCM waves with a characteristic intensity and length.
Definition: scale.h:46
void printInfo()
Definition: voice.cpp:193
void clear()
Definition: voice.cpp:182
#define MESSAGE
Definition: voice.cpp:32
Voice()
Constructor.
Definition: voice.cpp:45
#define ERROR
Definition: voice.cpp:34
void signalArtificialSoundGenerationComplete(bool)
#define STATUS
Definition: voice.cpp:31
int mSampleRate
Definition: voice.h:75
bool read(QIODevice &iodevice)
Definition: voice.cpp:117
static bool read(QIODevice &iodevice, const T &object)
QVector< double > mRecordedPitchInCents
Definition: voice.h:79
QVector< Scale > mScales
Definition: voice.h:78
static bool write(QIODevice &iodevice, const T &object)