340 lines
5.7 KiB
C++
340 lines
5.7 KiB
C++
/*
|
|
WDL - scalafile.h
|
|
(c) Theo Niessink 2012
|
|
<http://www.taletn.com/>
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
|
|
This file provides a class for read/writing Scala scale (.scl) files.
|
|
<http://www.huygens-fokker.org/scala/scl_format.html>
|
|
|
|
|
|
Example #1:
|
|
|
|
// Read scale file
|
|
|
|
#include "scalafile.h"
|
|
|
|
ScalaScaleFile scl;
|
|
scl.Open("myscale.scl");
|
|
scl.SkipDescr();
|
|
|
|
int n = scl.ReadNum();
|
|
for (int i = 0; i < n; ++i)
|
|
{
|
|
double pitch = scl.ReadPitch();
|
|
if (pitch > 0.) printf("%f\n", pitch);
|
|
}
|
|
|
|
Example #2:
|
|
|
|
// Write (create) scale file
|
|
|
|
#include "scalafile.h"
|
|
#include <math.h>
|
|
|
|
ScalaScaleFile scl;
|
|
char* filename = "newscale.scl";
|
|
scl.Create(filename);
|
|
scl.WriteFilename(filename);
|
|
scl.WriteDescr("New scale");
|
|
|
|
int n = 12;
|
|
scl.WriteNum(n);
|
|
for (int i = 1; i < n; ++i)
|
|
{
|
|
scl.WriteCents((double)(i * 100));
|
|
}
|
|
scl.WriteRatio(2, 1 , "octave");
|
|
|
|
*/
|
|
|
|
|
|
#ifndef _WDL_SCALA_FILE_H_
|
|
#define _WDL_SCALA_FILE_H_
|
|
|
|
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
class ScalaScaleFile
|
|
{
|
|
public:
|
|
ScalaScaleFile(): m_fp(NULL) {}
|
|
|
|
~ScalaScaleFile()
|
|
{
|
|
if (m_fp) fclose(m_fp);
|
|
}
|
|
|
|
bool Open(const char* filename)
|
|
{
|
|
m_fp = fopen(filename, "rb");
|
|
m_buf = EOF;
|
|
return (bool)m_fp;
|
|
}
|
|
|
|
int ReadDescr(char* buf, int size)
|
|
{
|
|
int c = SkipComments();
|
|
if (c == EOF) return 0;
|
|
|
|
int n = 0;
|
|
while (c != '\n' && c != EOF)
|
|
{
|
|
if (++n < size) *buf++ = c;
|
|
c = GetChar();
|
|
}
|
|
|
|
if (size) *buf = '\0';
|
|
return ++n;
|
|
}
|
|
|
|
inline int SkipDescr()
|
|
{
|
|
return ReadDescr(NULL, 0);
|
|
}
|
|
|
|
int ReadNum()
|
|
{
|
|
const int err = -1;
|
|
|
|
char buf[16];
|
|
if (!ReadVal(buf, sizeof(buf))) return err;
|
|
|
|
return atoi(buf);
|
|
}
|
|
|
|
double ReadPitch()
|
|
{
|
|
const double err = 0.;
|
|
|
|
char buf[32];
|
|
if (!ReadVal(buf, sizeof(buf))) return err;
|
|
|
|
double pitch;
|
|
if (strchr(buf, '.'))
|
|
{
|
|
double cents = atof(buf);
|
|
pitch = pow(2., cents / 1200.);
|
|
}
|
|
else
|
|
{
|
|
int num = atoi(buf);
|
|
if (num <= 0) return err;
|
|
char* slash = strchr(buf, '/');
|
|
if (slash)
|
|
{
|
|
int denom = atoi(slash + 1);
|
|
if (denom <= 0) return err;
|
|
pitch = (double)num / (double)denom;
|
|
}
|
|
else
|
|
{
|
|
pitch = (double)num;
|
|
}
|
|
}
|
|
|
|
return pitch;
|
|
}
|
|
|
|
bool Create(const char* filename)
|
|
{
|
|
if (m_fp) fclose(m_fp);
|
|
m_fp = fopen(filename, "w");
|
|
return (bool)m_fp;
|
|
}
|
|
|
|
inline int WriteComment(const char* buf)
|
|
{
|
|
return m_fp ? WriteLine(buf) : -1;
|
|
}
|
|
|
|
int WriteFilename(const char* filename)
|
|
{
|
|
if (!m_fp) return -1;
|
|
|
|
int ret = fputs("! ", m_fp);
|
|
|
|
if (ret >= 0)
|
|
{
|
|
const char* p = filename + strlen(filename);
|
|
while (--p >= filename && *p != '\\' && *p != '/');
|
|
ret = fputs(++p, m_fp);
|
|
}
|
|
|
|
if (ret >= 0) ret = fputs("\n", m_fp);
|
|
return ret;
|
|
}
|
|
|
|
inline int WriteDescr(const char* buf)
|
|
{
|
|
return m_fp ? WriteLine(buf) : -1;
|
|
}
|
|
|
|
int WriteNum(int num)
|
|
{
|
|
if (!m_fp) return -1;
|
|
return fprintf(m_fp, "%d\n", num);
|
|
}
|
|
|
|
int WriteCents(double cents, const char* comment = NULL)
|
|
{
|
|
if (!m_fp) return -1;
|
|
return WritePitchComment(fprintf(m_fp, "%0.5f", cents), comment);
|
|
}
|
|
|
|
int WriteRatio(int num, int denom, const char* comment = NULL)
|
|
{
|
|
if (!m_fp) return -1;
|
|
return WritePitchComment(fprintf(m_fp, "%d/%d", num, denom), comment);
|
|
}
|
|
|
|
int WritePitch(double pitch, const char* comment = NULL)
|
|
{
|
|
if (!m_fp) return -1;
|
|
|
|
double i;
|
|
int ret;
|
|
if (modf(pitch, &i) == 0.)
|
|
ret = fprintf(m_fp, "%0.0f/1", i);
|
|
else
|
|
ret = fprintf(m_fp, "%0.5f", log(pitch) / log(2.) * 1200.);
|
|
|
|
return WritePitchComment(ret, comment);
|
|
}
|
|
|
|
int Close()
|
|
{
|
|
if (m_fp)
|
|
{
|
|
if (fclose(m_fp)) return EOF;
|
|
m_fp = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
protected:
|
|
int GetChar()
|
|
{
|
|
int c = m_buf;
|
|
if (c != EOF)
|
|
{
|
|
m_buf = EOF;
|
|
return c;
|
|
}
|
|
|
|
c = m_fp ? fgetc(m_fp) : EOF;
|
|
if (c == EOF) return c;
|
|
|
|
switch (c)
|
|
{
|
|
case '\r':
|
|
m_buf = fgetc(m_fp);
|
|
if (m_buf == '\n') m_buf = EOF;
|
|
c = '\n';
|
|
break;
|
|
case '\n':
|
|
m_buf = fgetc(m_fp);
|
|
if (m_buf == '\r') m_buf = EOF;
|
|
break;
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
int SkipComments()
|
|
{
|
|
int c = GetChar();
|
|
while (c == '!')
|
|
{
|
|
do
|
|
{
|
|
c = GetChar();
|
|
if (c == EOF) return c;
|
|
} while (c != '\n');
|
|
c = GetChar();
|
|
}
|
|
return c;
|
|
}
|
|
|
|
int ReadVal(char* buf, int size)
|
|
{
|
|
int c = SkipComments();
|
|
if (c == EOF) return 0;
|
|
|
|
int n = 0;
|
|
bool ignore = false;
|
|
while (c != '\n' && c != EOF)
|
|
{
|
|
if (!ignore)
|
|
{
|
|
if (c != ' ' && c != '\t')
|
|
{
|
|
if (++n < size) *buf++ = c;
|
|
}
|
|
else if (n)
|
|
{
|
|
ignore = true;
|
|
}
|
|
}
|
|
c = GetChar();
|
|
}
|
|
if (n >= size) return 0;
|
|
|
|
*buf = '\0';
|
|
return ++n;
|
|
}
|
|
|
|
int WriteLine(const char* buf)
|
|
{
|
|
// if (!m_fp) return -1;
|
|
|
|
if (buf)
|
|
{
|
|
int ret = fputs(buf, m_fp);
|
|
if (ret < 0) return ret;
|
|
}
|
|
|
|
return fputs("\n", m_fp);
|
|
}
|
|
|
|
int WritePitchComment(int ret, const char* comment)
|
|
{
|
|
// if (!m_fp) return -1;
|
|
|
|
if (comment && ret >= 0)
|
|
{
|
|
ret = fputs(" ", m_fp);
|
|
if (ret >= 0) ret = fputs(comment, m_fp);
|
|
}
|
|
|
|
if (ret >= 0) ret = fputs("\n", m_fp);
|
|
return ret;
|
|
}
|
|
|
|
FILE* m_fp;
|
|
int m_buf;
|
|
};
|
|
|
|
|
|
#endif // _WDL_SCALA_FILE_H_
|