All pastes #2047569 Raw Edit

Stuff

public java v1 · immutable
#2047569 ·published 2011-04-17 23:28 UTC
rendered paste body
module alsatest;import std.string, std.math, std.random, std.time;alias Sample = short;class Sound {  void open() { writeln "unoverridden open()! "; _interrupt 3; }  void close() { writeln "unoverridden close()! ";  _interrupt 3; }  Sample[] copydump;  void writeCopydump(int len) { writeln "unoverridden writeCopydump()! ";  _interrupt 3; }  void dump(Sample delegate(int) dg, int newlen, float mult) {    if (copydump.length < newlen) copydump = new Sample[newlen];    for int i <- 0..newlen {      auto value = Sample:short:int:(dg(i) * mult);      copydump[i] = value;    }    writeCopydump(newlen);  }  void dump(Sample[] data, float mult) {    if (copydump.length < data.length) copydump = new Sample[data.length];    for int i <- 0..data.length      copydump[i] = Sample:short:int:(data[i]*mult);    writeCopydump(data.length);  }}c_include "alsa/pcm.h";extern(C) {  int snd_pcm_open(snd_pcm_t** pcm, char* name, int stream, int mode);  int snd_pcm_set_params(snd_pcm_t*, int, int, int channels, int rate, int soft_resample, int latency);  int snd_pcm_writei(snd_pcm_t*, void* buffer, int size);  char* snd_strerror(int);}template check(alias A) <<EOT  void check(ParamTypes type-of &A a) {    auto res = A a;    if res == 0 return;    else raise-error new Error "While calling $(string-of A): $res: $(CToString snd_strerror res)";  }EOTcontext Stream {  alias Playback = 0;}context SndFormat {  alias Unknown = -1;  alias S8 = 0; alias U8 = 1;  alias S16_LE = 2; alias S16_BE = 3;  alias U16_LE = 4; alias U16_BE = 5;}context Access {  alias MMap_Interleaved = 0; alias MMap_NonInterleaved = 1; alias MMap_Complex = 2;  alias RW_Interleaved = 3; alias RW_NonInterleaved = 4;}class AlsaSound : Sound {  snd_pcm_t* hdl;  string name;  void init(string n) { name = n; }  void open() {    auto foo = Stream.Playback;    check!snd_pcm_open(&hdl, toStringz name, Stream.Playback,  0);    check!snd_pcm_set_params(hdl, SndFormat.S16_LE, Access.RW_Interleaved, 1, 48000, 1, 400000);    check!snd_pcm_nonblock(hdl, false);  }  void close() {    check!snd_pcm_close(hdl);    hdl = null;  }  void writeCopydump(int len) {    bool closeAfter;    if !hdl { open(); closeAfter = true; }    onExit if (closeAfter) close();    auto cd = copydump[0 .. len];    while true {      // writeln "< $(cd.length)";      // writeln "$cd";      auto frames = snd_pcm_writei(hdl, cd.ptr, cd.length);      if (frames < 0) {        writeln "Attempt to recover: $frames";        frames = snd_pcm_recover(hdl, frames, 0);      }      if (frames < 0) {        writeln "Write failure! ";        return;      }      if (frames < cd.length) {        writeln "Short write: expected $(cd.length), got $frames";        cd = cd[frames .. $];      }      return;    }  }}class Note {  float maxVolume, sustain;  float decayStart, sustainStart, releaseStart;  float end;  float freq;  float calcVolume(float pos) {    if pos < decayStart      return pos * maxVolume / decayStart;    if pos < sustainStart      return maxVolume - (pos - decayStart) * (maxVolume - sustain) / (sustainStart - decayStart);    if pos < releaseStart      return sustain;    if pos < end      return sustain - (pos - releaseStart) * sustain / (end - releaseStart);    return 0;  }  float baseCalc(float pos) { writeln "baseCalc in note: need override"; _interrupt 3; }  float calcValue(float pos) {    // auto val = sin(pos * freq * 2 * PI);    auto val = baseCalc pos;    val = val * 2 - 1;    return val * calcVolume(pos);  }  bool contains(float f) { return eval f >= 0 && f < end; }}class SineNote : Note {  float baseCalc(float pos) {    return sin(pos * freq * 2 * PI);  }}class RectNote : Note {  float baseCalc(float pos) {    auto p2 = pos * freq;    auto val = (p2 - floorf p2);    if val > 0.5 val = 1;    else val = 0;    return val;  }}class KarplusStrongNote : Note {  float[] samples;  float prevInt, prevRes;  float baseCalc(float pos) {    int length = int:(48000 / freq);    if !samples.length {      samples = new float[length];      auto rng = getPRNG 23;      for int i <- 0..length        samples[i] = randf(rng) * 2 - 1;      prevInt = 0; prevRes = 0;    }    int c = int:(pos * freq * length) % length, d = (c + 1) % length;    samples[d] = (samples[c] + samples[d]) * 0.5 * 0.999;    alias C = 0.5;    auto res = samples[d];    (float prev, prevInt) = (prevInt, res);    res = C * res + prev - C * prevRes;    prevRes = res;    return res;  }}void cfgNote(Note res, float freq, float len) {  res.freq = freq;  using res {    maxVolume = 0.2;    sustain = 0.1;    decayStart = len * 0.05;    sustainStart = len * 0.3;    releaseStart = len * 0.7;    end = len;  }}template qsort(alias Smaller) << EOT1  template qsort(T) << EOT2    void qsort(T array) {      void qsort_recurse(int from, to) {        if (to == from || to == from + 1) return;        if (to == from + 2) {          if (!mixin(Smaller.replace("%a", "array[from]").replace("%b", "array[to - 1]")))            array[(from, to - 1)] = array[(to - 1, from)];          return;        }        int pivot = (to + from) / 2;        auto pival = array[pivot];        array[(pivot, to - 1)] = array[(to - 1, pivot)];        pivot = to - 1;        auto store = from;        // thanks wp        for int i <- from..to {          if (mixin(Smaller.replace("%a", "array[i]").replace("%b", "pival"))) {            array[(i, store)] = array[(store, i)];            store ++;          }        }        array[(store, pivot)] = array[(pivot, store)];        qsort_recurse(from, store);        qsort_recurse(store, to);      }      qsort_recurse(0, array.length);    }  EOT2EOT1void main() {  auto snd = new AlsaSound("default");  snd.open();  float delegate(float) dg;  int length = 1024;  int fadeout = 4096;  float[12] scale;  for int i <- 0..12    scale[i] = pow(pow(2, 1/12f), i);    (Note, float)[] notelist;  void addNoteAt(float start, float freq, float length) {    // writeln "addNoteAt($start, $freq, $length)";    (Note, float)[auto~] res;    for int i <- 0..notelist.length res ~= notelist[i];    Note n = new KarplusStrongNote;    cfgNote(n, freq, length);    res ~= (n, start);    notelist = res[];  }  void addNoteAtRef(float* pp, float freq, float len) {    alias pos = *pp;    addNoteAt(pos, freq, len);    pos += len;  }  void clearList(float pos) {    (Note, float)[auto~] res;    for int i <- 0..notelist.length {      alias n = notelist[i];      if pos < (n[1] + n[0].end) res ~= n;    }    notelist = res[];  }  void sortList() {    qsort!"eval (%a[1]) < (%b[1])" notelist;    for int i <- 1..notelist.length {      if (notelist[i-1][1] > notelist[i][1]) {        writeln "ERROR IN QUICKSORT AT $i. ";        _interrupt 3;       }    }  }  void addTrack(string notes) {    float baseFreq = 220;    float len = 0.3705;    int octaves; // int so it doesn't get fucked up by repeated mul/div    float lenf = 1;    float offs = 0;    alias state = (baseFreq, len, lenf, offs);    type-of state[] stack;    char lastChar;    while notes.length {      (char cur, notes) = notes[(0, 1..$)];      if cur == "."[0] { lenf = 1.5; }      else {        auto l = len * lenf;        void handleChar(char ch) {               if ch == "c" addNoteAtRef(&offs, baseFreq * scale[0], l);          else if ch == "d" addNoteAtRef(&offs, baseFreq * scale[2], l);          else if ch == "e" addNoteAtRef(&offs, baseFreq * scale[4], l);          else if ch == "f" addNoteAtRef(&offs, baseFreq * scale[5], l);          else if ch == "g" addNoteAtRef(&offs, baseFreq * scale[7], l);          else if ch == "a" addNoteAtRef(&offs, baseFreq * scale[9], l);          else if ch == "b" addNoteAtRef(&offs, baseFreq * scale[10], l);          else if ch == "h" addNoteAtRef(&offs, baseFreq * scale[11], l);          else if ch == "_" offs += l;          else if ch == ">" octaves ++;          else if ch == "<" octaves --;          else if ch == "+" len *= 2;          else if ch == "-" len /= 2;          else if ch == "[" stack ~= (baseFreq, len, lenf, offs);          else if ch == "]" stack = stack[0 .. $-1];          else if ch == "," (baseFreq, len, lenf, offs) = stack[$-1];        }        if (cur >= "0" && cur <= "9") {          int num = cur - "0";          while notes.length && notes[0] >= "0" && notes[0] <= "9" {            num = num * 10 + (notes[0] - "0");            notes = notes[1 .. $];          }          for 0..(num - 1)            handleChar lastChar;        } else handleChar cur;        lastChar = cur;        lenf = 1;        baseFreq = 220 * pow(2, octaves);      }    }  }  // addTrack "<a>e<h>ec-de+dg-aeh>c<h->c<h+agegde+.c<-h+ a>e<h>ec-de+dg-aeh>c<h->c<h+ag++a";  // addTrack "<+fgaefgaefgaefg+a";  string str = "-efef+ga-efef+ga-cdcd+ef-cdcd+fe", st2;  for 0..8 st2 ~= str;  st2 ~= "-c8d8<b8f4e4>c8d8<b8++fg--b8>c8<a8>d4c4<b8>c8<a8>d4c4<b14__+>";  for 0..2 st2 ~= str;  st2 ~= "-_>[f16,c16]  [d16,<a16>][f16,c16]  [d14__,<a14__>]<+";  st2 ~= "- <[f16,>c16<][d16,a16]  [f16,>c16<][d15,a15]+>";  for 0..2 st2 ~= str;  st2 ~= "-<b8>c8<a8>d4c4<b8>c8<a8>d4c4<b14__+>";  addTrack st2;  sortList();  writeln "added $(notelist.length) notes";  int lastDoneAt;  dg = delegate float(float f) {    float res = 0f;    bool done;    int i;    while !done && i < notelist.length {      alias n = notelist[i];      if (f >= n[1]) {        if f < n[1] + n[0].end res += n[0].calcValue (f - n[1]);      } else {        done = true;        auto doneAt = i;        if (doneAt != lastDoneAt) clearList f;        lastDoneAt = doneAt;      }      i++;    }    return res;  };  int base;  while true {    snd.dump(delegate Sample(int i) {      auto res = Sample:short:int:(dg((base + i) / 48000f) * 32767f);      return res;    }, length, 1f);    base += length;  }  snd.close();}