読者です 読者をやめる 読者になる 読者になる

よくわかる現代魔法1話の姉原美鎖の使ったプログラムソース

Programming Anime C++

一部勝手補完して作ってみた。

このソースの出典だけど、u8とかs16とかの型名から、Linuxカーネルかと思ったけどカーネルにC++使わないので関係なくて、他にああいう型名が既定で定義されているのはGBA/NDSプログラミングっぽいので、そっちまわりのサンプルソースとか調べてみたんだけど見つからなかった。

あとKodersとかDebian Source Searchでも調べたけど引っかからなかったので、自作である可能性が高いかも。

音声関連のソースであるということから考慮しても、GBA/NDSプログラミングで自作したという可能性が高いのではないかと思う。

なお、アニメ中でforループ内のインデントが崩れていた件については、タブストップ8、インデント2で保存されたものをタブストップ2で読みだしたため、4インデントされてるforの中身が下がってしまったと考えるのが適切だと思う。こういうことがあるからタブはちゃんとスペースに展開しなきゃいけないんですよ。

template <int NUMSAMPLES, class DECODER>
class Voice {
protected:
  DECODER* dec;
public:
  typedef DECODER Decoder;
  enum {
    SAMPLES = NUMSAMPLES,
  };

  Voice() : dec(&DECODER::null) {}
  DECODER* decoder() const          {return dec;}
  DECODER* decoder(Decoder* newdec) {return dec=newdec;}
  void ready() {}

  class Monoral : public Voice {
    s16 ce[SAMPLES];
  public:
    void ready() {
      for (int i = dec->decodeTo(ce, SAMPLES); i < SAMPLES; i++) {
	ce[i] = 0;
      }
    }
    s16 center(u16 i) const { return ce[i]; }
    s16 left(u16 i)   const { return ce[i]; }
    u16 right(u16 i)  const { return ce[i]; }
  };

  class Stereo : public Voice {
    s16 le[SAMPLES];
    s16 ri[SAMPLES];
  public:
    void ready() {
      for (int i = dec->decodeTo(le, ri, SAMPLES); i < SAMPLES; i++) {
	le[i] = ri[i] = 0;
      }
    }
    s16 center(u16 i) const { return ((s32)le[i] + (s32)ri[i])/2; }
    s16 left(u16 i)   const { return le[i]; }
    s16 right(u16 i)  const { return ri[i]; }
  };
};

template <int NUMVOICES, class VOICE>
class Mixer {
protected:
  VOICE vocs[NUMVOICES]:
  static inline u8 s16_u8(int v) { return u8(v/256+128); }
public:
  typedef VOICE Voice;
  typedef typename Voice::Decoder Decoder;

  enum{
    VOICES  = NUMVOICES,
    SAMPLES = Voice::SAMPLES,
  };

  Decoder* decoder(u16 i) const         { return i<VOICES ? vocs[i].decoder() : &Decoder::null; }
  Decoder* decoder(u16 i, Decoder* dec) { return i<VOICES ? vocs[i].decoder(dec) : &Decoder::null; }
  void mix() {}

  class Monoral : public Mixer {
    u8 ce[SAMPLES];
  public:
    void mix() {
      for (int i = 0; i < VOICES; i++) {
	vocs[i].ready();
      }
      for (int i = 0; i < SAMPLES; i++) {
	int v = 0;
	if (VOICES >= 1) { v += vocs[0].center(i); }
	if (VOICES >= 2) { v += vocs[1].center(i); }
	if (VOICES >= 3) { v += vocs[2].center(i); }
	if (VOICES >= 4) { v += vocs[3].center(i); }
	if (VOICES >= 5) { v += vocs[4].center(i); }
	if (VOICES >= 6) { v += vocs[5].center(i); }
	if (VOICES >= 7) { v += vocs[6].center(i); }
	if (VOICES >= 8) { v += vocs[7].center(i); }
	ce[i] = s16_u8(v/VOICES);
      }
    }
    const u8* center() const { return ce; }
    const u8* left()   const { return ce; }
    const u8* right()  const { return ce; }
  };

  class Stereo : public Mixer {
    u8 le[SAMPLES];
    u8 ri[SAMPLES];
  public:
    void mix() {
      for (int i = 0; i < VOICES; i++) {
	vocs[i].ready();
      }
      for (int i = 0; i < SAMPLES; i++) {
	s16 v = 0;
	if (VOICES >= 1) { v += vocs[0].left(i); }
	if (VOICES >= 2) { v += vocs[1].left(i); }
	if (VOICES >= 3) { v += vocs[2].left(i); }
	if (VOICES >= 4) { v += vocs[3].left(i); }
	if (VOICES >= 5) { v += vocs[4].left(i); }
	if (VOICES >= 6) { v += vocs[5].left(i); }
	if (VOICES >= 7) { v += vocs[6].left(i); }
	if (VOICES >= 8) { v += vocs[7].left(i); }
	le[i] = s16_u8(v/VOICES);
	v = 0;
	if (VOICES >= 1) { v += vocs[0].right(i); }
	if (VOICES >= 2) { v += vocs[1].right(i); }
	if (VOICES >= 3) { v += vocs[2].right(i); }
	if (VOICES >= 4) { v += vocs[3].right(i); }
	if (VOICES >= 5) { v += vocs[4].right(i); }
	if (VOICES >= 6) { v += vocs[5].right(i); }
	if (VOICES >= 7) { v += vocs[6].right(i); }
	if (VOICES >= 8) { v += vocs[7].right(i); }
	ri[i] = s16_u8(v/VOICES);
      }
    }
    s16 center(u16 i) const { return ((s32)le[i] + (s32)ri[i])/2; }
    const u8* left()  const { return le; }
    const u8* right() const { return ri; }
  }
};