смена голоса на ардуино

ferot7a37
Offline
Зарегистрирован: 25.03.2018

всем привет, прошу помощи и советов, захотел сделать такую штуковину которая будет менять голос - что когда говоришь в микрофон то на динамик выходит например грубый или какойто другой голос , с другим тоном. это вообще возможно сделать на ардуино? или направьте что и где мне искать?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Искать в гугле по тэгу вокодер.

Да и на ардуино это вряд ли получится - копайте в сторону процессоров, изначально работающих с аналоговыми сигналами типа ямахи.

И еще - Вы пишете не в том разделе - ЗДЕСЬ ТОЛЬКО РЕАЛИЗОВАННЫЕ ПРОЕКТЫ.

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

ferot7a37 пишет:
это вообще возможно сделать на ардуино?

Нет, ардуино не потянет обработку звука. Она для этого не предназначена.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ferot7a37 пишет:

захотел сделать такую штуковину которая будет менять голос..

....направьте что и где мне искать?

Знакомых в прокуратуре и хорошего адвоката. ;)))))

ku-ku
Offline
Зарегистрирован: 14.11.2018

ferot7a37 пишет:
или направьте что и где мне искать?

в китайских магазинах лет 10 назад покупал. Одна в виде коробочка, с две трети спичечного. Вторая - в виде сердечка примерно того же размера. Там вроде был наушник и гнездо для микрофона. Плюс в самой штуке микрофон. Говоришь, а она в гнездо реверберированный голос шлет.

Погугли алгоритмы звуковых эффектов. Я не аккустик, но вроде pitch, reverberator и т.п. они называются. Берешь аналоговые данные, меняешь и на другой аналоговый пин посылаешь. Но на ардуине это будет в два спичечных коробка наверно. Боторейка нужна хорошая, плюс усилок, плюс ардуина. Короче, имхо негоже это дело на ардуине городить.

alex_r61
alex_r61 аватар
Offline
Зарегистрирован: 20.06.2012

 Простейшую обработку делал ещё на Z80. Через АЦП загонял фразу в ОЗУ и там обрабатывал. Чистил от шумов, уменьшал или увеличивал громкость и др. Выводил через ЦАП, а изменяя скорость
вывода получал слегка изменённый голос.

ku-ku
Offline
Зарегистрирован: 14.11.2018

на спектруме была програмка, которая генерила из текста голос. Я их тогда кучку опробовал, но была одна, которая весьма неплохо справлялась. Ну, было вполне похоже (особенно с учетом тех технологий).
Собственно, название не помню, но в память мне она въелась из-за размера. Если тот же Zynaps загружался, скажем, три минуты, то та програмулька грузилась не более 10-ти секунд. По объему я не в курсе, сколько это в байтах, но полагаю невероятно мало.

Волшебник
Offline
Зарегистрирован: 22.12.2016
ferot7a37
Offline
Зарегистрирован: 25.03.2018

спс по видео вроде понятно, но скачанный zip вайл по вашей ссылке пустой. Что делать?

Волшебник
Offline
Зарегистрирован: 22.12.2016

Поменяйте браузер.

Сам скетч могу запостить и здесь:

/*
 ***********  VOICE SCRAMBLER / PITCH SHIFTING (RADIX 4 FFT)  Arduino Application. ***********
 * LINK: http://coolarduino.wordpress.com/2012/04/09/voice-pitch-shifting-scrambler/ 
 *
 * Created for  Arduino UNO board: Anatoly Kuzmenko 9 Apr. 2012 
 *                                 k_anatoly@hotmail.com
 *
 * SOFTWARE COMPILES USING Arduino 0022 IDE (Tested on Linux OS only).
 * !!! IDE 1.0 mixed up TIMER2 settings, some modification would be necessary in
 * the ISR, responsible for sampling / replayiying.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute copies of the Software, 
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *
 * Copyright (C) 2012 Anatoly Kuzmenko.
 * All Rights Reserved.
 ********************************************************************************************
 */

#include <avr/pgmspace.h>
#include <avr/interrupt.h>
//#pragma GCC optimize (always_inline)

#define FFT_SIZE       128                  // 64 : 4 kHz = 16 msec. time sapling period.
#define LOG_2_FFT        7                  /* log2 FFT_SIZE */
#define NWAVE          256                  /* full length of Sinewave[] */
#define TIMER2         194; //133           // 8 kHz       // Adjustment timing to ~4 kHz.

//const prog_int16_t Sinewave[NWAVE] PROGMEM = {
const int16_t Sinewave[NWAVE] PROGMEM = {

      +0,      +6,     +13,     +19,     +25,     +31,     +37,     +44,     +50,     +56,     +62,     +68,     +74,     +80,     +86,     +92,
     +98,    +103,    +109,    +115,    +120,    +126,    +131,    +136,    +142,    +147,    +152,    +157,    +162,    +167,    +171,    +176,
    +180,    +185,    +189,    +193,    +197,    +201,    +205,    +208,    +212,    +215,    +219,    +222,    +225,    +228,    +231,    +233,
    +236,    +238,    +240,    +242,    +244,    +246,    +247,    +249,    +250,    +251,    +252,    +253,    +254,    +254,    +255,    +255,
    +255,    +255,    +255,    +254,    +254,    +253,    +252,    +251,    +250,    +249,    +247,    +246,    +244,    +242,    +240,    +238,
    +236,    +233,    +231,    +228,    +225,    +222,    +219,    +215,    +212,    +208,    +205,    +201,    +197,    +193,    +189,    +185,
    +180,    +176,    +171,    +167,    +162,    +157,    +152,    +147,    +142,    +136,    +131,    +126,    +120,    +115,    +109,    +103,
     +98,     +92,     +86,     +80,     +74,     +68,     +62,     +56,     +50,     +44,     +37,     +31,     +25,     +19,     +13,      +6,
      +0,      -6,     -13,     -19,     -25,     -31,     -38,     -44,     -50,     -56,     -62,     -68,     -74,     -80,     -86,     -92,
     -98,    -104,    -109,    -115,    -121,    -126,    -132,    -137,    -142,    -147,    -152,    -157,    -162,    -167,    -172,    -177,
    -181,    -185,    -190,    -194,    -198,    -202,    -206,    -209,    -213,    -216,    -220,    -223,    -226,    -229,    -231,    -234,
    -237,    -239,    -241,    -243,    -245,    -247,    -248,    -250,    -251,    -252,    -253,    -254,    -255,    -255,    -256,    -256,
    -256,    -256,    -256,    -255,    -255,    -254,    -253,    -252,    -251,    -250,    -248,    -247,    -245,    -243,    -241,    -239,
    -237,    -234,    -231,    -229,    -226,    -223,    -220,    -216,    -213,    -209,    -206,    -202,    -198,    -194,    -190,    -185,
    -181,    -177,    -172,    -167,    -162,    -157,    -152,    -147,    -142,    -137,    -132,    -126,    -121,    -115,    -109,    -104,
     -98,     -92,     -86,     -80,     -74,     -68,     -62,     -56,     -50,     -44,     -38,     -31,     -25,     -19,     -13,      -6
};

#define mult_shf_s16x16( a, b)    \
({                        \
int prod, val1=a, val2=b; \
__asm__ __volatile__ (    \ 
"muls %B1, %B2	\n\t"     \
"mov %B0, r0    \n\t"	  \ 
"mul %A1, %A2   \n\t"	  \ 
"mov %A0, r1    \n\t"     \ 
"mulsu %B1, %A2	\n\t"     \ 
"add %A0, r0    \n\t"     \ 
"adc %B0, r1    \n\t"     \ 
"mulsu %B2, %A1	\n\t"     \ 
"add %A0, r0    \n\t"     \ 
"adc %B0, r1    \n\t"     \ 
"clr r1         \n\t"     \ 
: "=&d" (prod)            \
: "a" (val1), "a" (val2)  \
);                        \
prod;                     \
})

static inline void mult_shf_I( int c, int s, int x, int y, int &u, int &v)  __attribute__((always_inline));
static inline void mult_shf_I( int c, int s, int x, int y, int &u, int &v)
{
  u = (mult_shf_s16x16(x, c) - mult_shf_s16x16(y, s));    
  v = (mult_shf_s16x16(y, c) + mult_shf_s16x16(x, s));    // Hardcoded >>8 bits, use with 8-bits Sinewave ONLY.
}

static inline void sum_dif_I(int a, int b, int &s, int &d)  __attribute__((always_inline));
static inline void sum_dif_I(int a, int b, int &s, int &d)
{
  s = (a+b);   
  d = (a-b); 
}

void rev_bin( int *fr, int fft_n)
{
    int m, mr, nn, l;
    int tr;

    mr = 0;
    nn = fft_n - 1;

    for (m=1; m<=nn; ++m) {
            l = fft_n;
         do {
             l >>= 1;
            } while (mr+l > nn);

            mr = (mr & (l-1)) + l;

        if (mr <= m)
             continue;
            tr = fr[m];
            fr[m] = fr[mr];
            fr[mr] = tr;
    }
}

void fft8_dit_core_p1(int *fr, int *fi)
{
    int plus1a, plus2a, plus3a, plus4a, plus1b, plus2b;
    int mins1a, mins2a, mins3a, mins4a, mins1b, mins2b, mM1a, mM2a;

    sum_dif_I(fr[0], fr[1], plus1a, mins1a);
    sum_dif_I(fr[2], fr[3], plus2a, mins2a);
    sum_dif_I(fr[4], fr[5], plus3a, mins3a);
    sum_dif_I(fr[6], fr[7], plus4a, mins4a);

    sum_dif_I(plus1a, plus2a, plus1b, mins1b);
    sum_dif_I(plus3a, plus4a, plus2b, mins2b);

    sum_dif_I(plus1b, plus2b, fr[0], fr[4]);
    sum_dif_I(mins3a, mins4a, mM1a, mM2a);

    int prib1a, prib2a, prib3a, prib4a, prib1b, prib2b;
    int otnt1a, otnt2a, otnt3a, otnt4a, otnt1b, otnt2b, oT1a, oT2a;

    sum_dif_I(fi[0], fi[1], prib1a, otnt1a);
    sum_dif_I(fi[2], fi[3], prib2a, otnt2a);
    sum_dif_I(fi[4], fi[5], prib3a, otnt3a);
    sum_dif_I(fi[6], fi[7], prib4a, otnt4a);

    sum_dif_I(prib1a, prib2a, prib1b, otnt1b);
    sum_dif_I(prib3a, prib4a, prib2b, otnt2b);

    sum_dif_I(prib1b, prib2b, fi[0], fi[4]);
    sum_dif_I(otnt3a, otnt4a, oT1a, oT2a);

    mM2a   =    mult_shf_s16x16(mM2a, 181);
    sum_dif_I(mins1a,   mM2a, plus1a, plus2a);

    prib2b =    mult_shf_s16x16(oT1a, 181);
    sum_dif_I(otnt2a, prib2b, mins3a, plus3a);

    sum_dif_I(plus1a, mins3a, fr[7], fr[1]);
    sum_dif_I(mins1b, otnt2b, fr[6], fr[2]);
    sum_dif_I(plus2a, plus3a, fr[3], fr[5]);

    oT2a   =    mult_shf_s16x16(oT2a, 181);
    sum_dif_I( otnt1a,   oT2a, plus1a, plus2a);

    plus2b =    mult_shf_s16x16(mM1a, 181);
    sum_dif_I(-mins2a, plus2b, plus3a, mins3a);

    sum_dif_I(plus1a, mins3a, fi[7], fi[1]);
    sum_dif_I(otnt1b,-mins2b, fi[6], fi[2]);
    sum_dif_I(plus2a, plus3a, fi[3], fi[5]);
}

void fft_radix4_I( int *fr, int *fi, int ldn)
{
    const int n = (1UL<<ldn);
    int ldm = 0, rdx = 2;

    ldm = (ldn&1);
    if ( ldm!=0 )
    {
        for (int i0=0; i0<n; i0+=8)
        {
            fft8_dit_core_p1(fr+i0, fi+i0);
        }
    }
    else
       {
    for (int i0 = 0; i0 < n; i0 += 4)
        {
            int xr,yr,ur,vr, xi,yi,ui,vi;

            int i1 = i0 + 1;
            int i2 = i1 + 1;
            int i3 = i2 + 1;

            sum_dif_I(fr[i0], fr[i1], xr, ur);
            sum_dif_I(fr[i2], fr[i3], yr, vi);
            sum_dif_I(fi[i0], fi[i1], xi, ui);
            sum_dif_I(fi[i3], fi[i2], yi, vr);

            sum_dif_I(ui, vi, fi[i1], fi[i3]);
            sum_dif_I(xi, yi, fi[i0], fi[i2]);
            sum_dif_I(ur, vr, fr[i1], fr[i3]);
            sum_dif_I(xr, yr, fr[i0], fr[i2]);
        }
       }    
    for (ldm += 2 * rdx; ldm <= ldn; ldm += rdx)
    {
        int m = (1UL<<ldm);
        int m4 = (m>>rdx);

        int phI0 =  NWAVE / m;                            
        int phI  = 0;

        for (int j = 0; j < m4; j++)
        {
        int c,s,c2,s2,c3,s3;

         s  = pgm_read_word(&Sinewave[   phI]);
         s2 = pgm_read_word(&Sinewave[ 2*phI]);
         s3 = pgm_read_word(&Sinewave[ 3*phI]);

         c  = pgm_read_word(&Sinewave[   phI + NWAVE/4]);
         c2 = pgm_read_word(&Sinewave[ 2*phI + NWAVE/4]);
         c3 = pgm_read_word(&Sinewave[ 3*phI + NWAVE/4]);

       for (int r = 0; r < n; r += m)    
       {
                int i0 = j + r;
                int i1 = i0 + m4;
                int i2 = i1 + m4;
                int i3 = i2 + m4;

           int xr,yr,ur,vr, xi,yi,ui,vi;

             mult_shf_I( c2, s2, fr[i1], fi[i1], xr, xi);
             mult_shf_I(  c,  s, fr[i2], fi[i2], yr, vr);
             mult_shf_I( c3, s3, fr[i3], fi[i3], vi, yi);

             int t = yi - vr;
                yi += vr;
                vr = t;

                ur = fr[i0] - xr;
                xr += fr[i0];

              sum_dif_I(ur, vr, fr[i1], fr[i3]);

                 t = yr - vi;
                yr += vi;
                vi = t;

                ui = fi[i0] - xi;
                xi += fi[i0];

              sum_dif_I(ui, vi, fi[i1], fi[i3]);
              sum_dif_I(xr, yr, fr[i0], fr[i2]);
              sum_dif_I(xi, yi, fi[i0], fi[i2]);
            }
          phI += phI0;
        }
    }
}

void scrambl( int *ar_r, int *ar_i, int fft_sz, int revr)
{ 
    int  mirror = fft_sz / 2;
    int  tmp, indx1, indx2, indx3, indx4;

    if ( !revr ) {
        for( int i = 1; i < fft_sz; i++ ) {
            indx1 = mirror - i;
            if ( indx1 < 0 ) indx1 = fft_sz + indx1;

            if ( i >= indx1 ) continue;
            tmp = ar_r[i];
              ar_r[i] = ar_r[indx1];
              ar_r[indx1] = tmp;

            tmp = ar_i[i];
              ar_i[i] = ar_i[indx1];
              ar_i[indx1] = tmp;
      }
    }
   else
    {  
    int  frr[FFT_SIZE/2] = {0}, fii[FFT_SIZE/2] = {0};

    for( int i = 1; i < mirror; i++ ) {

        indx2 = (i * ( 7 + revr)) >> 3;// [1 + 1..9] * X / 8

        if((indx2 < mirror) && (indx2 > 0))
        {
         frr[indx2] =  ar_r[i];
         fii[indx2] =  ar_i[i];
        }
      }
    for ( int  i = 1; i < mirror; i++)
      {
        indx4      = fft_sz - i;
        ar_r[i]    =  frr[i];
        ar_i[i]    =  fii[i];
        ar_r[indx4]    =  frr[i];
        ar_i[indx4]    =  -fii[i];
      }
   }
}

static inline int del_round ( int delit, int denom )  __attribute__((always_inline));
static inline int del_round ( int delit, int denom )
{
    if (delit < 0) delit = ((delit>>denom) +1);
    else delit = delit >> denom;

    return delit;
}

void prnt_out( int *f_r, int *f_i) {
      for (int i = 0; i < FFT_SIZE; i++){
        Serial.print("\t");
        Serial.print( f_r[i], DEC );     
        if ((i+1)%16 == 0) Serial.print("\n");
      } // Prosmotr dannuh massiva polychennogo posle FFT
      Serial.print("\n");
      for (int i = 0; i < FFT_SIZE; i++){
        Serial.print("\t");
        Serial.print( f_i[i], DEC );     
        if ((i+1)%16 == 0) Serial.print("\n");
      } // Prosmotr dannuh massiva polychennogo posle FFT
      Serial.print("\n");
}

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}
//**************************************************************************************************
          int16_t   f_r[FFT_SIZE]   =   { 0};
          int16_t   f_i[FFT_SIZE]   =   { 0};
          int16_t   yot[FFT_SIZE]   =   { 0};            // PWM Output array
volatile  int16_t   xin[FFT_SIZE]   =   { 0};            // ADC Sampling array
          
volatile  uint8_t         process   = 0;                 // Flag "new samples ready"
volatile uint16_t         n_sampl   = 0;                 // Sampling counter

const     int16_t         sdvigDC   = 512;               // DC offset
          uint8_t    incomingByte;      
          uint8_t       scrmbl_sw   = 0;               
          uint8_t       pitch_shf   = 0;               
          uint8_t      prnt_spktr   = 0;               
          uint8_t      prnt_scrmb   = 0;               
          uint8_t      prnt_yotta   = 0;               
          int16_t  yot2[FFT_SIZE]   =   { 0};            // PWM Output Debug (continuity buffer)
          
void setup() {
  Serial.begin(115200);  
  pinMode(12, OUTPUT);   //FFT-iFFT Performance check point
  pinMode( 5, OUTPUT);   //PWM HIGH BYTE
  pinMode( 6, OUTPUT);   //PWM LOW  BYTE

  TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
  TCCR2B &= ~(1<<WGM22);
  ASSR   &= ~(1<<AS2);
  TIMSK2  = 0;
  TIMSK0  = 0;
  TIMSK1  = 0;

  TCCR2B |= ((1<<CS21) | (1<<CS20));  
  TCCR2B &= ~(1<<CS22) ;                         // prescaler = 32, tick = 2 mikrosec.
  TCNT2   = TIMER2; 
  TIMSK2 |= (1<<TOIE2);

  ADCSRA  = 0x87;
  ADMUX   = 0x40;
  ADCSRA |= (1<<ADSC);
  
  TCCR0B &= ~((1<<CS02)  | (1<<CS01)); 
  TCCR0B |=   (1<<CS00);  

  TCCR0A &= ~((1<<WGM02) | (1<<WGM01));
  TCCR0B |=   (1<<WGM00);
  
  TCCR0A |=  ((1<<COM0A1) | (1<<COM0B1));
  TCCR0A &= ~((1<<COM0A0) | (1<<COM0B0));
  OCR0A   = 128;
  OCR0B   = 192;
}

void loop()
{
 if ( process )
 {
  digitalWrite(12, HIGH);
   for ( int i = 0; i < FFT_SIZE; i++ ) 
    {
     yot2[i] = yot[i];  
     yot[i]  = f_r[i];

     f_r[i] = xin[i];
     f_i[i] = 0;
    }    
     if (prnt_yotta){
       cli();
       prnt_out( yot2, yot );
       prnt_yotta = 0;
       sei();
     }
  
   rev_bin( f_r, FFT_SIZE);
   fft_radix4_I( f_r, f_i, LOG_2_FFT);

     if (prnt_spktr){
       cli();
       prnt_out( f_r, f_i );
       prnt_spktr = 0;
       sei();
     }
     
     if (scrmbl_sw){
       scrambl( f_r, f_i, FFT_SIZE, pitch_shf);
     } 

     if (prnt_scrmb){
       cli();
       prnt_out( f_r, f_i );
       prnt_scrmb = 0;
       sei();
     }
                                           //GAIN RESET
    for ( int  i = 0; i < FFT_SIZE; i++) {
     f_r[i] = del_round(f_r[i], 6);        
     f_i[i] = del_round(f_i[i], 6);
    }

   rev_bin( f_r, FFT_SIZE);
   rev_bin( f_i, FFT_SIZE);

   fft_radix4_I( f_i, f_r, LOG_2_FFT);     //REVERSE I-R ORDER MUST!
  digitalWrite(12, LOW);
 process = 0;
}

  //CONSOLE COMMAND LINE INTERFACE 

  if (Serial.available() > 0) {
    incomingByte = Serial.read();
    if (incomingByte == 'm') {             // FREE MEMORY BYTES 
      Serial.println(freeRam());
    }
    if (incomingByte == 'x') {
      for (int i = 0; i < FFT_SIZE; i++){
        Serial.print("\t");
        Serial.print( xin[i], DEC );
        if ((i+1)%16 == 0) Serial.print("\n");
      } 
      Serial.print("\n");
    }
    if (incomingByte == 's') {             // SWITCHES  -  SCRAMBLING  ON / OFF
       scrmbl_sw = 1 - scrmbl_sw;
        Serial.print("\tSwitch: ");
        Serial.println( scrmbl_sw, DEC );     
    }
    if (incomingByte == 'y') {
       prnt_yotta = 1;
    }
    if (incomingByte == 'f') {
       prnt_spktr = 1;
    }
    if (incomingByte == 'p') {
       prnt_scrmb = 1;
    }
    if ((incomingByte >= '0') && (incomingByte <= '9')) {
       pitch_shf = incomingByte - 48;
       Serial.print("\tPitch: ");
       Serial.println( pitch_shf, DEC );     
    }
  }
}

ISR(TIMER2_OVF_vect)
{
  TCNT2 = TIMER2;               
  if (ADCSRA & 0x10)
  {
    int16_t temp  = ADCL;  
            temp += (ADCH << 8);  
            temp -= sdvigDC;
 
    ADCSRA |= (1<<ADSC);

    xin[n_sampl]  = temp; 
       
    temp = yot2[n_sampl];
    temp += sdvigDC;

    OCR0A   = (temp & 0x1f); //pin 6 low  byte5/10
    OCR0B   = (temp  >> 5 ); //pin 5 high byte5/10

    n_sampl++;      
  }
  
  if ( n_sampl > (FFT_SIZE -1))
  {
    n_sampl = 0;
    process = 1;
  }
}