text: import wave
  import numpy as np
  import time
  from base import *
  from waves import *
  
  canon_1_2_2_3 = [
  # https://www.everyonepiano.com/Number-31-1-Canon-Pachelbels-Canon-Numbered-Musical-Notation-Preview-1.html
  '''
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
  +3 0 0 0+2 0 0 0  +1 0 0 0 7 0 0 0   6 0 0 0 5 0 0 0   6 0 0 0 7 0 0 0
  +3 0 0 0+2 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   6 0 0 0 5 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   6 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   6 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
  +3 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
  +3 0 0 0 0 0 0 0  +3 0 0 0 0 0 0 0  +1 0 0 0 0 0 0 0   6 0 0 0 0 0 0 0
  +3 0 0 0 0 0 0 0  +3 0 0 0 0 0 0 0  +1 0 0 0 0 0 0 0   6 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
  +1 0 0 0 0 0 0 0
  '''
  ,
  '''
   3 0 0 0 2 0 0 0   1 0 0 0-7 0 0 0  -6 0 0 0-5 0 0 0  -6 0 0 0-7 0 0 0
   5 0 0 0 5 0 0 0   3 0 0 0 3 0 0 0   1 0 0 0 1 0 0 0   1 0 0 0 2 0 0 0
   5 0 0 0 5 0 4 0  +1 0 0 0 7 0 5 0   6 0 0 0 5 0 3 0   4 0 0 0 2 0 4 0
  +1 7+1 3 5 0 7 0  +1 0+3 0+5+3+5+6  +4+3+2+4+3+2+1 7   6 4+1 0 7 5+1 7
  +1 7+1 3 5 0 7 0  +1 0+3 0+5+3+5+6  +4+3+2+4+3+2+1 7   6 5 4 0+1 0 7+2
  +3 0+3+1 0 0+4+2  +1 0+1 7 7 5 3 5   6 0 7+1 5 0 3 5   4 0 4+1+1 0 7+2
  +3 0+3+1 0 0+4+2  +1 0+1 7 7 5 3 5   6 0 7+1 5 0 3 5   4 0 4+1+1 0 7+2
  +5+3+5+3+5 6+1+3  +3+1+3 3 5 5 5 7   6+1 6 5 5 3 5 7   6+1+1 7 7 7+2+4
  +5+3+5+3+5 6+1+3  +3+1+3 3 5 5 5 7   6+1 6 5 5 3 5 7   6+1+1 7 7 7+2+4
  +3+1+3+2+2+1+3+1  +1 6+1 1 3 3 3 7   6+1 6 5 5 3 5 7   6+1+1 7 7+2 7 6
  +1 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0+3+5+3 0+2+4+2   0+1+3+1 0+3+1 7   0 6+1 6 0 5+1 5   0 6+1 7 0 6+2 7
   0+3+5+3 0+2+4+2   0+1+3+1 0+5+3+5  +6+6+4+6+5+5+3+5  +6+4+5+6+7+5 7+2
   5 0+3+1 0 0+3+2  +2 0+1 7 3 7+3+7  +7+5+5+3+3+1+1 6   6 4 6 6 7 5+1+2
  +1 0+3+4+5+6+5+4  +1 0+1+2+3+4+3+2   4 0 6+1+1 0+1 7   4 0 4+1+1 0 7+2
  +1 0+3+4+5+6+5+4  +1 0+1+2+3+4+3+2   4 0 6+1+1 0+1 7   4 0 4+1+1 0 7+2
  +3 0 0 0+2 0 0 0  +1 0 0 0 7 0 0 0   6 0 0 0 5 0 0 0   6 0 0 0 7 0 0 0
  +3 0 0 0+2 0 0 0  +1 0 0 0 7 0 0 0   6 0 0 0 5 0 0 0   6 0 0 0 7 0 0 0
   3 0 0 0 0 0 0 0
  '''
  ,
  '''
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 5 0 5
   0 5+2+2 0+3+3+3   0+1 0+1 0 3 0 0   0 0 0 0 0 0 0 0   0 0 6 0 0 7+1 5
   0 5+2+2 0+3+3+3   0+1 0+1 0 3 0 0   0 0 0 0 0 0 0 0   0 0 6 0 0 7+1 5
   0+4 0+4 7 7+2+4   0+2 0 4 6 4+1+1   0 7 0 4 4 4 6+1   0 7 0+1 6+1+3+5
   0+4 0+4 7 7+2+4   0+2 0 4 6 4+1+1   0 7 0 4 4 4 6+1   0 7 0+1 6+1+3+5
   0+2 0+1 7+2+2 7   0 7 0 2 4 2+1+1   0 7 0 4 4 4 6+1   0 7 0 6+1+1+1 7
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0+4 0 0 0+3 0 0   0+2 0 0 0+2 0 0   0 7 0 0 0 6 0 0   0 7 0 6 5 7 0 0
   0+4 0 0 0+3 0 0   6+2 0 0 0+4 0 0   0+5 0 0 0+4 0 0  +5+6+4+5+6 0+1 5
   0 0+2+2 0+3+4+3   0+1 0+1 5+1+5*1  +6+4+4+2+2 7 7 5   5 5 4+1 6+1 5 5
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 7+1+1+1+1+1   0 0 6+2 7 7+1 5
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 7+1+1+1+1+1   0 0 6+2 7 7+1 5
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0
  '''
  ,
  '''
  -1 0 0 0_5 0 0 0  _6 0 0 0_3 0 0 0  _4 0 0 0_5 0 0 0  _4 0 0 0_5 0 0 0
  -1 0 0 0_5 0 0 0  _6 0 0 0_3 0 0 0  _4 0 0 0-1 0 0 0  _4 0 0 0_5 0 0 0
  -1-5 1 3_7-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-3-5 1  _4-1-4-6_5-2-5-7
  -1-3-5 1_5-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-3-5 1  _4-1-4-6_5-2-5-7
  -1-3-5 1_5-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-3-5 1  _4-1-4-6_5-2-5-7
  -1-3-5 1_7-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-3-5 1  _4-1-4-6_5-2-5-7
  -1-3-5 1_5-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-3-5 1  _4-1-4-6_5-2-5-7
  -1-5 1 0_5-2-7 0  _6-3 1 0_3-3-5 0  _4-1-6 0-1-5 1 0  _4-1-6 0_5-2-7 0
  -1-5 1 0_5-2-7 0  _6-3 1 0_3-3-5 0  _4-1-6 0-1-5 1 0  _4-1-6 0_5-2-7 0
  -1-5 1 0_5-2-7 0  _6-3 1 0_3-3-5 0  _4-1-6 0-1-5 1 0  _4-1-6 0_5-2-7 0
  -1-5 1 3_5-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-5 1 3  _4-1-4-6_5-2-5-7
  -1-3-5 3_5-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-5 1 3  _4-1-4-6_5-2-5-7
  -1-3-5 3_5-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-5 1 3  _4-1-4-6_5-2-5-7
  -1-3-5 3_5-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-5 1 3  _4-1-4-6_5-2-5-7
  -1-3-5 3_5-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-5 1 3  _4-1-4-6_5-2-5-7
  -1-3-5 3_5-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-5 1 3  _4-1-4-6_5-2-5-7
  -1-3-5 1_7-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-3-5 1  _4-1-4-6_5-2-5-7
  -1-3-5 1_7-2-5-7  _6-3-6 1_3-3-5-7  _4-1-4-6-1-3-5 1  _4-1-4-6_5-2-5-7
  -1 0 0 0 0 0 0 0
  '''
  ]
  
  BASE_FREQUENCY = 261.626
  BASE_AMPLITUDE = 5000
  STRIDE_TIME = 0.25
  FRAMERATE = 44100
  
  if 1: tune_map = {'1':0, '2':2, '3':4, '4':5, '5':7, '6':9, '7':11}
  else: tune_map = {'1':0, '2':2, '3':3, '4':5, '5':7, '6':8, '7':10}
  
  x1, x21, x22, x3 = [tuneToLogFrequency(tune_seq, tune_map) for tune_seq in canon_1_2_2_3]
  
  def addBlank(seq):
      res = [None] * (len(seq) * 2)
      res[::2] = seq
      return res
  
  def join(seq1, seq2):
      assert(len(seq1) == len(seq2))
      res = [None] * (len(seq1) * 2)
      res[::2] = seq1
      res[1::2] = seq2
      return res
  
  if __name__ == '__main__':
      print('running...')
      start = time.time()
  
      log_frequencys_1_2_3 = [addBlank(x1), join(x21, x22), addBlank(x3)]
      durations = [STRIDE_TIME * 10] * len(log_frequencys_1_2_3[0])
  
      wavs = [logFrequencysToWave(log_frequencys, durations, BASE_FREQUENCY, BASE_AMPLITUDE, STRIDE_TIME, FRAMERATE
              , waveKalimba) for log_frequencys in log_frequencys_1_2_3]
      wav = sum(wavs[1:], wavs[0])
  
      assert(np.max(wav) < 32768)
      assert(np.min(wav) >= -32768)
      wav_short = wav.astype('<i2') # short
  
      with wave.open("canon_kalimba.wav", 'wb') as wf:
          wf.setnchannels(1)
          wf.setframerate(FRAMERATE)
          wf.setsampwidth(2) # short
          wf.writeframes(wav_short.tobytes())
  
      print(f'finished, time consumed: {time.time() - start} seconds')
  