Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #if 0
- #!/bin/sh
- exec c++ -Wall -std=c++11 "$0" -o `echo "$0" | sed -e s/\.[^\.]*$//g`
- exit
- #endif
- /*
- huumoriBiisi.cpp (F) Petteri Mรคki 2014
- This is free and unencumbered software released into the public domain.
- Anyone is free to copy, modify, publish, use, compile, sell, or
- distribute this software, either in source code form or as a compiled
- binary, for any purpose, commercial or non-commercial, and by any
- means.
- In jurisdictions that recognize copyright laws, the author or authors
- of this software dedicate any and all copyright interest in the
- software to the public domain. We make this dedication for the benefit
- of the public at large and to the detriment of our heirs and
- successors. We intend this dedication to be an overt act of
- relinquishment in perpetuity of all present and future rights to this
- software under copyright law.
- 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.
- For more information, please refer to <http://unlicense.org/>
- */
- #include <algorithm>
- #include <cmath>
- #include <cstdint>
- #include <deque>
- #include <fstream>
- #include <iostream>
- #include <map>
- #include <set>
- #include <sstream>
- #include <string>
- using namespace std;
- typedef float Real;
- typedef unsigned int uint;
- // Works with unsigned integers. Not sure about signed integers.
- template <typename integer>
- class little_endian {
- public:
- little_endian(integer x) {
- for (size_t i = 0; i < sizeof(integer); i++, x>>=8)
- data[i] = (x & 0xff);
- }
- operator integer () const {
- integer result = 0;
- for (size_t i = 0; i < sizeof(integer); i++)
- result |= (data[i] << (8*i));
- }
- private:
- uint8_t data[sizeof(integer)];
- };
- typedef little_endian<uint32_t> uint32le;
- typedef little_endian<uint16_t> uint16le;
- template <typename T>
- class Clamp {
- public:
- Clamp(const T & lower, const T & upper) : lower_(lower), upper_(upper) { }
- const T & operator()(const T & a) const { return a < lower_ ? lower_ : upper_ < a ? upper_ : a; }
- private:
- T lower_, upper_;
- };
- struct Snd_Buf {
- deque<Real> buf;
- uint smpl_Rt;
- };
- struct Note {
- uint8_t midiPitch;
- uint start, length;
- };
- struct Note_Compare{
- bool operator()(const Note & a, const Note & b) const {
- return a.start != b.start ? a.start < b.start : a.length != b.length ? a.length < b.length : a.midiPitch < b.midiPitch;
- }
- };
- typedef set<Note, Note_Compare> NoteSet;
- class WriteWav {
- public:
- template <class ByteWriter>
- static void execute(const Snd_Buf & sb, ByteWriter bw) {
- // https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
- // write as signed 16-bit mono PCM.
- writestr(bw, "RIFF");
- writeobjbytes(bw, uint32le(36+2*sb.buf.size()));
- writestr(bw, "WAVE");
- writestr(bw, "fmt ");
- writeobjbytes(bw, uint32le(16));
- writeobjbytes(bw, uint16le(1)); // PCM
- writeobjbytes(bw, uint16le(1)); // mono
- writeobjbytes(bw, uint32le(sb.smpl_Rt));
- writeobjbytes(bw, uint32le(2*sb.smpl_Rt));
- writeobjbytes(bw, uint16le(2));
- writeobjbytes(bw, uint16le(16));
- writestr(bw, "data");
- writeobjbytes(bw, uint32le(2*sb.buf.size()));
- for (Real smpl : sb.buf)
- writeobjbytes(bw, uint16le(0x7777*Clamp<Real>(-1.0, 1.0)(smpl)));
- }
- private:
- template <class ByteWriter, typename T>
- static void writeobjbytes(ByteWriter bw, const T & a) {
- for (size_t i =0; i < sizeof(T); i++)
- bw(((uint8_t*)&a)[i]);
- }
- template <class ByteWriter, class ByteSequence>
- static void writebytes(ByteWriter bw, const ByteSequence & a) {
- for_each(a.begin(), a.end(), bw);
- }
- template <class ByteWriter>
- static void writestr(ByteWriter bw, const string & a){
- writebytes(bw, a);
- }
- };
- /*
- Format of token: (~|([a-g][#b]?(,*|'*)|r)[1-9][0-9]*)
- The bind_next ('~') operator is currently a prefix notation,
- instead of the intended infix notation.
- */
- NoteSet parseSongstr(const string & songstr) {
- static const map<char, uint8_t> charPitches{ { 'a', 69 }, { 'b', 71 }, { 'c', 60 }, { 'd', 62 }, { 'e', 64 }, { 'f', 65 }, { 'g', 67 }, { 'r', 0 } };
- NoteSet result;
- istringstream iss(songstr);
- bool bind_next = false;
- uint time = 0;
- for (;;) {
- string token;
- iss >> token;
- if (token.empty())
- break;
- istringstream tok_iss(token);
- int pitchCh = tok_iss.get();
- // token '~' check
- if (pitchCh == EOF || charPitches.count(pitchCh) == 0) {
- if (pitchCh == '~' && tok_iss.get() == EOF) {
- bind_next = true;
- continue;
- }
- else
- break; // error.
- }
- bool rest = (pitchCh == 'r');
- int octaveShift = 0, semitoneShift = 0;
- if (!rest) {
- // [#b]?
- int c = tok_iss.peek();
- if (c == '#') {
- semitoneShift++;
- tok_iss.get();
- }
- else if (c == 'b') {
- semitoneShift--;
- tok_iss.get();
- }
- // (,*|'*)
- c = tok_iss.peek();
- if (c == ',' || c == '\'') {
- int shiftDir = (c == '\'' ? +1 : -1);
- do {
- octaveShift += shiftDir;
- tok_iss.get();
- } while (tok_iss.peek() == c);
- }
- }
- // length the Number
- uint length;
- tok_iss >> length;
- if (tok_iss.fail() && tok_iss.get() != EOF)
- break; // error
- if (!rest)
- result.insert(Note{ uint8_t(charPitches.at(pitchCh)+12*octaveShift+semitoneShift), time, length });
- if (!bind_next)
- time += length;
- bind_next = false;
- }
- return result;
- }
- const uint smpl_Rt = 88200;
- const uint sngLngth = 6;
- const Real timeunit_s = 1./6.;
- const Real volume = 0.5;
- // Joulupukki (C) P. J. Hannikainen
- // https://fi.wikipedia.org/wiki/P._J._Hannikainen
- // Copyright probably expired as of 1995.
- const string sng = "~ c,,6 c2 d1 e3 ~ e,,3 c3 ~ f,,9 a,2 b,1 c3 a,3 ~ g,,6 f2 e1 d2 c1 ~ e,,3 b,2 g,1 ~ c,,6 c3 c1";
- namespace waveform {
- Real sine(Real x) {
- return sin(2*M_PI*x);
- }
- Real saw(Real x) {
- return 2*(x-floor(x+Real(0.5)));
- }
- Real square(Real x) {
- return saw(x)-saw(x+Real(0.5));
- }
- Real triangle(Real x) {
- return 2*abs(saw(x+Real(.5)))-1;
- }
- }
- int main(int argc, char const * const * argv) {
- Snd_Buf sngSmpls{ deque<Real>(smpl_Rt*sngLngth), smpl_Rt };
- NoteSet notes(parseSongstr(sng));
- for (auto n : notes) {
- cerr << int(n.midiPitch) << ' ' << n.start << ' ' << n.length << endl;
- }
- for (auto n : notes) {
- try {
- for (size_t i = 0; i < n.length*timeunit_s*sngSmpls.smpl_Rt; i++)
- sngSmpls.buf.at(n.start*timeunit_s*sngSmpls.smpl_Rt + i) += volume*(1.-exp(-100.*((n.length*timeunit_s*sngSmpls.smpl_Rt)-i)/sngSmpls.smpl_Rt))*(1.-exp(-100.*Real(i)/sngSmpls.smpl_Rt))*(.5+.5*exp(-10.*Real(i)/sngSmpls.smpl_Rt))*waveform::saw(i/Real(sngSmpls.smpl_Rt)*pow(2, (n.midiPitch-69.)/12.)*440);
- } catch (exception & e) {
- cerr << e.what() << endl;
- }
- }
- WriteWav::execute(sngSmpls, [](char c){ cout.put(c); });
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement