0 Replies Latest reply on Mar 17, 2020 10:31 PM by MoTa_728816

    A Theremin Wannabe / なんちゃってルミン (CY8CKIT-044)

    MoTa_728816

      IMG_4154.JPG

      When I saw a proximity sample in the CY8CKIT-044 kit guide, I thought that I'd like to make a theremin alike.

      CY8CKIT-044 キットガイドに近接センサの例が紹介されているのをみて、テルミンのようなものを作ろうと思い立ちました。

       

      But with CapSense v7.0, I could not figure out how to extract the signal. (It should exist somewhere though)

      しかし CapSense v7.0 で信号値を直接読み出す方法が見つかりませんでした。 (きっとあるとは思うのですが・・・)

       

      When we use the CapSense Tuner, we see the "analog" signal.

      So the must the value somewhere..

      キャップセンスチューナーを使用すると、ちゃんと測定値が表示されています。

      ということはどこかにその値があるはずです。

      003-Sense_Tuner.JPG

       

      So I peeked the source of run_tuner() function and there it is.

      run_tuner() のソースを覗いてみたらありました。

       

      Note: To use the CapSense Tuner, please edit the file cs_utils.h and define USE_CAPSENSE_TUNER to 1u

      注:本プログラムでキャップセンスチューナーを使用する場合は、cs_utils.h 内の USE_CAPSENSE_TUNER を 1u に define してください。

       

      Now we have the input, so let's talk about the output.

      これで入力は確保できたので、出力のお話になります。

       

      In the Orgel Sample I wrote last year, I created the note table.

      去年、書いたオルゴールのサンプルで音階のテーブルが作ってありました。

      TSoC CY8C4146LQI-S433 4-Voice Orgel (四声のオルゴール)

       

      Although it had 54 notes (4 octaves?), since the effective distance range of proximity was not too large,

      assigning all notes to the signal value made it a chaos.

      テーブルには54の半音階音程 (4オクターブくらいかな?) あったのですが、近接センサの有効範囲が

      それほど広くなかったので、その範囲に全ての音を割り当てたらカオスになりました。

       

      As I chatted with my colleagues, I was suggested that notes enough for Froschgesang will be fine.

      同僚とチャットで相談したところ、カエルの歌が出来るくらいの音程範囲でいいんじゃね?と助言されました。

       

      So I reduced the table to just about 1 octave.

      Then the output was much more bearable.

      という訳で音程数を一オクターブ程度にしてみました。

      すると出音は少しマシになってくれました。

      ========================

      note_type note3[] = { /* 1 octave only */

      /*   count,    freq,      name */

          {    0,    0.00, "Rest"   }, /*  0 */

          { 9555, 1046.50, "C6"     }, /* 33 */

          { 8513, 1174.66, "D6"     }, /* 35 */

          { 7584, 1318.51, "E6"     }, /* 37 */

          { 7158, 1396.91, "F6"     }, /* 38 */

          { 6377, 1567.98, "G6"     }, /* 40 */

          { 5681, 1760.00, "A6"     }, /* 42 */

          { 5061, 1975.53, "B6"     }, /* 44 */

          { 4777, 2093.00, "C7"     }, /* 45 */

          { 4256, 2349.32, "D7"     }, /* 47 */

          { 3792, 2637.02, "E7"     }, /* 49 */

          { 3579, 2793.83, "F7"     }, /* 50 */

          { 3188, 3135.96, "G7"     }, /* 52 */

          { 2840, 3520.00, "A7"     }  /* 54 */

      } ;

      ========================

       

      The real(?) Theremin has 2 handles, left one for volume and the right one for note (height).

      本物(?)のテルミンでは2本腕があって、左側が音量、右側が音程になっているようです。

       

      Although I can not control volume as I cheated by using PWM to generate sound,

      I used the left hand sensor as volume. (For the time being only ON and OFF)

      音の発生に PWM を使って手抜きをしてしまっているため音量の調整は出来ないのですが、

      臨場感(?)の為に左側のセンサは音量に割り当てました。(今のところオンとオフしかできません)

       

      Now the project...

      さてプロジェクトですが・・・

       

      schematic

      001-schematic.JPG

      pins

      002-pins.JPG

      main.c

      =================

      #include "project.h"

      #include <stdio.h>

      #include <stdbool.h>

      #include "tty_utils.h"

      #include "cs_utils.h"

      #include "note.h"

       

      #define TONE_MIN 0

      #define TONE_MAX 500

       

      #define VOLUME_MIN 100

      #define VOLUME_MAX 500

       

      #define TONE_OFFSET 0

      #define MAX_NOTE 54

       

      void init_hardware(void)

      {

          CyGlobalIntEnable; /* Enable global interrupts. */   

         

      #if USE_CAPSENSE_TUNER

          EZI2C_Start() ;

      #else

          tty_init() ;

          splash("A Thermin Wannabe") ;

      #endif

          prepare_buffer() ;

         

          PWM_Start() ;

         

          CapSense_Start() ;          /* Initialize CapSense Component */

          CapSense_ScanAllWidgets() ; /* Scan all widgets */

      }

       

      void play_note(uint16_t tone_value, uint16_t volume_value)

      {

          static uint16_t prev_tone = 0 ;

          static uint16_t prev_volume = 0 ;

          uint16_t tone_index ;

          uint16_t note_delta ;

         

          if (tone_value > TONE_MAX) {

              tone_value = TONE_MAX ;

          }

          if (tone_value < 0 ) {

              tone_value = 0 ;

          }

          note_delta = (TONE_MAX - TONE_OFFSET) / num_notes ;

         

          tone_index = TONE_OFFSET + tone_value / note_delta ;

          if (tone_index >= num_notes) {

              tone_index = num_notes - 1 ;

          }

         

          if ((prev_tone == tone_index) && (prev_volume == volume_value)) {

              return ;

          }

       

          if ((volume_value > VOLUME_MIN) && (prev_tone != tone_index)) {

              print(note[tone_index].name) ;

              print("\n\r") ;

          }

       

          prev_tone = tone_index ;

          prev_volume = volume_value ;

         

          PWM_Stop() ;

          PWM_WritePeriod(note[tone_index].count) ;

          PWM_WriteCompare(note[tone_index].count / 2) ;

          if (volume_value > VOLUME_MIN) {

              PWM_Enable() ;

          }

      }

       

      int main(void)

      {

          uint32 proxy_tone = 0 ;

          uint32 proxy_volume = 0 ;

         

          init_hardware() ;

         

          for(;;) {

              if (CapSense_IsBusy() == CapSense_NOT_BUSY) {

                  CapSense_ProcessAllWidgets() ;

                 

                  proxy_volume = CapSense_IsProximitySensorActive(

                                      CapSense_PROXIMITY0_WDGT_ID,

                                      CapSense_PROXIMITY0_SNS0_ID) ;

       

       

                  proxy_volume = CapSense_IsProximitySensorActive(

                                      CapSense_PROXIMITY0_WDGT_ID,

                                      CapSense_PROXIMITY0_SNS1_ID) ;

      #if !USE_CAPSENSE_TUNER           

      //            snprintf(str, STR_BUF_LEN, "Tone: %u  Volume: %u\n\r",

      //                cs_signal[0], cs_signal[1]) ;

      //            print(str) ;

                  play_note(cs_signal[0], cs_signal[1]) ;

      #endif

                 

                  cs_tuner() ;

                  CapSense_ScanAllWidgets() ;

              }

          }

      }

      =================

       

      Tera Term log

      Barely played the first part of the Froschgesang. (C, D, E, F, E, D, C)

       

      テラタームの出力

      かろうじてカエルの歌の冒頭を弾いた(?)ところ。(ド、レ、ミ、ファ、ミ、レ、ド)

      000-TeraTerm.JPG

      At first I was trying to control by using only my index finger and it was very difficult,

      but later I found that using palm makes control much easier.

       

      最初、人差し指だけで制御しようとしたら非常に難しかったのですが、

      手のひらを使うと随分と楽になることがわかりました。

       

      moto

      P.S. CY8CKIT-044 with 2 proximity sensor wire looks like a Kirkaldyia deyrolli.

      https://en.wikipedia.org/wiki/Lethocerus_deyrollei

       

      追伸 プロキシミティセンサ用の線を二本付けている CY8CKIT-044 はなんかタガメに似ています。

      https://ja.wikipedia.org/wiki/%E3%82%BF%E3%82%AC%E3%83%A1