YMZ294で2音以上鳴らす時の注意

まずは完成形から。ファイナルファンタジーIの「プレリュード」です。
矩形波1をメロディに、そこから8分音符1個分ずらして矩形波2をエコー的に使っています。

スケッチはこんな感じ。


#include <Metro.h>
#include <YMZ294.h>
#include <mml.h>

// YMZ294 defines
const byte WRCS_PIN = 8;
const byte A0_PIN = 9;
const byte RESET_PIN = 11;
static YMZ294 ymz(WRCS_PIN, A0_PIN, RESET_PIN);

Metro psgMetro[2] = {Metro(), Metro()};

// mml defines
MML mml[2];
MML_OPTION mmlopt;

char *text[2] = {
  "o5 l16 b-cdf b->cdf b->cdf b->cdf b-fdc< b-fdc< b-fdc< b-fdc gab-d gab->d gab->d gab->d gd<b-a gd<b-a gd<b-a gdb-a",
  "o5 l16 b-a b-cdf b->cdf b->cdf b->cdf b-fdc< b-fdc< b-fdc< b-fdc gab-d gab->d gab->d gab->d gd<b-a gd<b-a gd<b-a gd"
};

static Channel ch[2] = {CH_A, CH_B};
static void mml_callback(MML_INFO *p, void *extobj)
{
  Channel* c = (Channel*)extobj;
  switch (p->type) {
    case MML_TYPE_NOTE:
      {
      MML_ARGS_NOTE *args = &(p->args.note);
      snd(args->number, args->ticks, *c);
      }
      break;
    case MML_TYPE_REST:
      {
      MML_ARGS_REST *args = &(p->args.rest);
      snd(0, args->ticks, *c);
      }
      break;
    default:
      snd(0,0,*c);
      break;
  }
}

void snd(int num, int ms, Channel ch)
{
  if (num == 0)
    ymz.SetFreqBit(ch, 0);
  else{
    ymz.SetFrequency(ch, noteFreq[num]);
  }
  psgMetro[ch].interval(ms);
}

void setup() {
  DDRD = 0b11111111;
  pinMode(WRCS_PIN, OUTPUT);
  pinMode(A0_PIN, OUTPUT);
  pinMode(RESET_PIN, OUTPUT);

  ymz.SetMixer(0b111, 0b100);
  ymz.SetVolume(CH_A, 0b0111);
  ymz.SetVolume(CH_B, 0b0111);
  
  MML_OPTION_INITIALIZER(&mmlopt, 5, 8, 600);
  for (int i = 0; i < 2; i++){
    ymz.SetEnvEnable((Channel)i, false);
    mml_init(&mml[i], mml_callback, &ch[i]);
    snd(0, 0, (Channel)i);
    mml_setup(&mml[i], &mmlopt, text[i]);
  }
}

void loop() {
  for (int i = 0; i < 2; i++){
    if (psgMetro[i].check() == 1){
      if(mml_fetch(&mml[i]) != MML_RESULT_OK){
        snd(0, 0, (Channel)ch[i]);
        mml_setup(&mml[i], &mmlopt, text[i]);
      }
    }
  }
} 

大事なのがここ。
ymz.SetVolume(CH_A, 0b0111);
ymz.SetVolume(CH_B, 0b0111);
チャンネルごとのボリュームは0~15で指定できるんですが、2chとも15(0b1111)に指定すると、音割れが発生します。
ボリュームの代わりにエンベロープを指定しても同様に音割れします。

というわけで、2chともボリュームを7(0b0111)に設定して、代わりにHT82V739を使った簡単なアンプを通しています。
HT82V739_photo HT82V739_breadboard HT82V739_circuit
Arduinoから5VとGNDをアンプに接続して、半固定抵抗にYMZ294の出力(5番ピン)を接続します。
HT82V739からの出力は、1番ピンと7番ピンです。

というような回路を通すと
この記事の最初に載せた、割れてない音が出せます。

ところで、本当はHT82V739を2基使って、前回の魔界塔士サガの曲をアンプ経由で鳴らしたいと思っていたのですが……
なんというか、リアルイルーム音楽としか言い様のないような禍々しい音が流れてきたので、記事の内容を変更したのでした。
何をどう間違ったらこんな音になるんだ。
※再生はあまりオススメしません

コメントを残す