/***************************************************************************
 * Devry Senior Project
 * Title: Darth Elvis Voice Manipulation System
 *
 * License:
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   as published by the Free Software Foundation; either version 2
 *   of the License, or (at your option) any later version.
 *   
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *   
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Description:
 *  - This program was originally copied from Rockbox v2.5 recording.c, although over 90% of the code has been gutted
 *  - This program continuously loops accepting keypad input and updating the display
 *  - The user can adjust the baseline gain, volume, bass, and treble settings
 *  - Each cycle this thread sleeps for PERIOD/MAX_STEPS time segments
 *  - The user can adjust the period.
 *  - The user can adjust random changes added to the period each cycle
 *  - On each cycle the volume, bass, and treble can be automatically adjusted to cause distortion
 *  - The distortion is created by different waveforms that can be applied to volume, bass, and treble
 *  - The magnitude of the distortion can be adjusted
 *  - Press F3 to toggle debug info
 *
 * Version History:
 *   2006May23 : Travis Sidelinger : Created from recording.c
 *   2006May25 : Travis Sidelinger : Fixed to the point where it compiles
 *   2006Jun10 : Travis Sidelinger : Working distortion waves
 *   2006Jun11 : Travis Sidelinger : Removed global vars, created dist_wave function, moved display function into main loop
 *   2006Jun14 : Travis Sidelinger : Fixed panic on shutdown, fixed crash on exit and re-entering DEVMS
 *   2006Jun14 : Travis Sidelinger : Fixed tri dist equation
 *   2006Jun15 : Travis Sidelinger : Removed the recording app to free up space, fixed sin wave mode
 *   2006Jun15 : Travis Sidelinger : Added random phase sin mode, Added rand period setting
 *
 *
 ****************************************************************************/
 
/* Includes */
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
 
#include "config.h"
#include "system.h"
#include "lcd.h"
#include "led.h"
#include "mpeg.h"
#include "audio.h"
#include "mp3_playback.h"
#include "button.h"
#include "kernel.h"
#include "settings.h"
#include "font.h"
#include "misc.h"
#include "tree.h"
#include "string.h"
#include "dir.h"
#include "errno.h"
#include "talk.h"
#include "sound.h"
#include "ata.h"
#include "devms.h"
#include "mathf.h"
#include "math.h"
 
/******************************************************************************/
/* Global Variables */
 
#define SOURCE_MIC   0
#define SOURCE_LINE  1
#ifdef HAVE_SPDIF_IN
#define SOURCE_SPDIF 2
#define MAX_SOURCE   SOURCE_SPDIF
#else
#define MAX_SOURCE   SOURCE_LINE
#endif
 
#define DEBUG_DEVMS YES
 
/* Modes */
#define MODE_GAIN   0
#define MODE_VOL    1
#define MODE_BASS   2
#define MODE_TREB   3
#define MODE_PRD    4
#define MODE_RPRD    5
#define MODE_DEV    6
#define MODE_VOLD   7
#define MODE_BASD   8
#define MODE_TRBD   9
 
/* Distortion Modes */
#define DIST_MODE_NONE    0
#define DIST_MODE_SAW     1
#define DIST_MODE_TRI     2
#define DIST_MODE_SIN     3
#define DIST_MODE_SQR     4
#define DIST_MODE_RAND    5
#define DIST_MODE_RANDTRI 6
#define DIST_MODE_RANDSIN 7
 
/* Limits */
#define MAX_GAIN          15
#define MAX_VOL           96
#define MAX_BASS          15
#define MAX_TREB          15
#define MAX_PRD           128
#define MAX_RPRD          64
#define MAX_DEV           128
#define MAX_DIST_MODES    8
#define MAX_MODES         10
#define MAX_STEPS         15
 
/* Default values */
#define DEFAULT_GAIN      10
#define DEFAULT_VOL       70
#define DEFAULT_BASS      7
#define DEFAULT_TREB      7
#define DEFAULT_PRD       1024
#define DEFAULT_RPRD      0
#define DEFAULT_DEV       16
#define DEFAULT_VOLD      0
#define DEFAULT_BASD      0
#define DEFAULT_TRBD      0
 
/******************************************************************************/
/* Mode control function
 *
 * This funtion checks limit and sets the mode values
 */
void mode_set_values(short modes[], short dist_value[])
{
    /** Variables **/
    auto unsigned short local_vol  = 0;
    auto unsigned short local_bass = 0;
    auto unsigned short local_treb = 0;
 
    /** Main **/
 
    /*
      These limits are enforced in one location because both user input and distortion mode fuctions
      can change these values.  It may be better performance to check them locally when changing a
      value, but it is easier to enforce them here
    */
 
    /* Limit minimum values */
    if(modes[MODE_GAIN] < 0) { modes[MODE_GAIN] = MAX_GAIN        ; }  /* Gain Control   */
    if(modes[MODE_VOL]  < 0) { modes[MODE_VOL]  = MAX_VOL         ; }  /* Volume Control */
    if(modes[MODE_BASS] < 0) { modes[MODE_BASS] = MAX_BASS        ; }  /* Bass Control   */
    if(modes[MODE_TREB] < 0) { modes[MODE_TREB] = MAX_TREB        ; }  /* Treble Control */
    if(modes[MODE_PRD]  < 0) { modes[MODE_PRD]  = MAX_PRD         ; }  /* Period Control */
    if(modes[MODE_RPRD] < 0) { modes[MODE_RPRD] = MAX_RPRD        ; }  /* Random Period Control */
    if(modes[MODE_DEV]  < 0) { modes[MODE_DEV]  = MAX_DEV         ; }  /* Deviation Control */
    if(modes[MODE_VOLD] < 0) { modes[MODE_VOLD] = MAX_DIST_MODES-1; }  /* Volume Deviation Control */
    if(modes[MODE_BASD] < 0) { modes[MODE_BASD] = MAX_DIST_MODES-1; }  /* Bass Deviation Control */
    if(modes[MODE_TRBD] < 0) { modes[MODE_TRBD] = MAX_DIST_MODES-1; }  /* Treble Deviation Control */
 
    /* Limit max values */
    if(modes[MODE_GAIN] > MAX_GAIN)         { modes[MODE_GAIN] = 0; }  /* Gain Control   */
    if(modes[MODE_VOL]  > MAX_VOL)          { modes[MODE_VOL]  = 0; }  /* Volume Control */
    if(modes[MODE_BASS] > MAX_BASS)         { modes[MODE_BASS] = 0; }  /* Bass Control   */
    if(modes[MODE_TREB] > MAX_TREB)         { modes[MODE_TREB] = 0; }  /* Treble Control */
    if(modes[MODE_PRD]  > MAX_PRD)          { modes[MODE_PRD]  = 0; }  /* Period Control */
    if(modes[MODE_RPRD] > MAX_RPRD)         { modes[MODE_RPRD] = 0; }  /* Random Period Control */
    if(modes[MODE_DEV]  > MAX_DEV)          { modes[MODE_DEV]  = 0; }  /* Deviation Control */
    if(modes[MODE_VOLD] > MAX_DIST_MODES-1) { modes[MODE_VOLD] = 0; }  /* Volume Deviation Control */
    if(modes[MODE_BASD] > MAX_DIST_MODES-1) { modes[MODE_BASD] = 0; }  /* Bass Deviation Control */
    if(modes[MODE_TRBD] > MAX_DIST_MODES-1) { modes[MODE_TRBD] = 0; }  /* Treble Deviation Control */
 
    /* Determine distorted values */
    local_vol  = modes[MODE_VOL]  + (dist_value[MODE_VOL]  >> 1);
    local_bass = modes[MODE_BASS] + (dist_value[MODE_BASS] >> 1);
    local_treb = modes[MODE_TREB] + (dist_value[MODE_TREB] >> 1);
 
    /* Limit max values after appling distortion */
    if(local_vol  > MAX_VOL)  { local_vol  = MAX_VOL;  }  /* Volume Control */
    if(local_bass > MAX_BASS) { local_bass = MAX_BASS; }  /* Bass Control   */
    if(local_treb > MAX_TREB) { local_treb = MAX_TREB; }  /* Treble Control */
 
    /* Mic Gain */
    if(global_settings.rec_source == SOURCE_MIC)
    {
        mpeg_set_recording_gain(modes[MODE_GAIN] + dist_value[MODE_GAIN], 0, true);
        }
    else
    {
        mpeg_set_recording_gain(modes[MODE_GAIN] + dist_value[MODE_GAIN], modes[MODE_GAIN] + dist_value[MODE_GAIN], false);
        }
 
    /* Apply actual changes to volume */
    sound_set(SOUND_VOLUME, local_vol);
    sound_set(SOUND_BASS,   local_bass);
    sound_set(SOUND_TREBLE, local_treb);
 
    /** End **/
    return;
    }
 
/******************************************************************************/
/* Main loop fuction
 *
 * This start Rockbox in recording mode, then loops processing each keypress
 * Each cycle the display is updated and distortion is calculated
 */
bool devms_main(void)
{
    /*** Variables ***/
    auto long button;
    auto bool done = false;
    auto bool debug = false;
    auto char buf[32];                                              /* Display charactor buffer */
    auto unsigned short i = 0;                                      /* counter */
    auto unsigned short step_position = 0;                          /* Tracks the position in each cycle of distortion wave */
    auto short input_selected = 0;                                  /* Select input */
    auto short modes[MAX_MODES]  =                                  /* The value of each mode */
        {
            DEFAULT_GAIN,
            DEFAULT_VOL,
            DEFAULT_BASS,
            DEFAULT_TREB,
            DEFAULT_PRD,
            DEFAULT_RPRD,
            DEFAULT_DEV,
            DEFAULT_VOLD,
            DEFAULT_BASD,
            DEFAULT_TRBD
            };
    auto short dist_value[MAX_DIST_MODES+1]  = {0,0,0,0,0};         /* Distortion or deviated sound values */
    auto int lcd_char_weight, lcd_char_height;
    auto char mode_displayed[MAX_MODES];
    auto char dist_names[MAX_DIST_MODES][5] =                       /* Names for each distortion value */
        {
            "none",
            "saw",
            "tri",
            "sin",
            "sqr",
            "rand",
            "rtri",
            "rsin"
            };
 
    /*** Main ***/
 
    srand(HZ);  /* seed random numbers */
 
    /* Display Setup */
    lcd_setfont(FONT_SYSFIXED);
    lcd_getstringsize("X", &lcd_char_weight, &lcd_char_height);
    lcd_setmargins(global_settings.invert_cursor ? 0 : lcd_char_weight, 8);
 
    /* Recording Setup */
#if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR)
    ata_set_led_enabled(true);
#endif
    mpeg_init_recording();
 
    if (global_settings.rec_prerecord_time) { talk_buffer_steal(); } /* will use the mp3 buffer */
    mpeg_set_recording_options(global_settings.rec_frequency,
                               global_settings.rec_quality,
                               global_settings.rec_source,
                               global_settings.rec_channels,
                               global_settings.rec_editable,
                               global_settings.rec_prerecord_time);
 
    settings_apply_trigger();
    /* mpeg_pause_recording(); */
 
    /* Main Loop, get keypad input, update display, apply distortion */
    while(!done)
    {
        /* Set audio values */
        mode_set_values(modes, dist_value);
 
        /* Draw the display */
 
        if(debug || step_position == 0)   /* Only update the display once every cycle for performance */
        {
            /* Postion the position pointer on the selected mode */
            for(i=0;i<=MAX_MODES-1;i++) { mode_displayed[i] = ' '; } /* clear the array */
            mode_displayed[input_selected] = '+';
 
            switch(input_selected)
            {
                case MODE_GAIN: mode_displayed[input_selected] = 'G'; break;
                case MODE_VOL:  mode_displayed[input_selected] = 'V'; break;
                case MODE_BASS: mode_displayed[input_selected] = 'B'; break;
                case MODE_TREB: mode_displayed[input_selected] = 'T'; break;
                }
 
            lcd_clear_display();
            if(debug)
            {
                /* Debug Info */
                snprintf(buf, sizeof(buf), " StepVollBassTreb");
                lcd_putsxy(0,lcd_char_height*0,buf);
 
                snprintf(buf, sizeof(buf), "% %03d %03d %03d %03d", step_position, dist_value[MODE_VOL], dist_value[MODE_BASS], dist_value[MODE_TREB]);
                lcd_putsxy(0,lcd_char_height*1,buf);
                }
            else 
            {
                /* Normal Info */
                snprintf(buf, sizeof(buf), " GainVollBassTreb");
                lcd_putsxy(0,lcd_char_height*0,buf);
 
                snprintf(buf, sizeof(buf), "%c%03d %03d %03d %03d",mode_displayed[MODE_GAIN] | mode_displayed[MODE_VOL] | mode_displayed[MODE_BASS] | mode_displayed[MODE_TREB],
                    modes[MODE_GAIN],
                    modes[MODE_VOL],
                    modes[MODE_BASS],
                    modes[MODE_TREB]
                    );
                lcd_putsxy(0,lcd_char_height*1,buf);
                }
 
            snprintf(buf, sizeof(buf), "%cPeriod:      %d", mode_displayed[MODE_PRD], modes[MODE_PRD] * 10);
            lcd_putsxy(0,lcd_char_height*2,buf);
 
            snprintf(buf, sizeof(buf), "%cRand Period: %d", mode_displayed[MODE_RPRD],modes[MODE_RPRD] * 10);
            lcd_putsxy(0,lcd_char_height*3,buf);
 
            snprintf(buf, sizeof(buf), "%cDeviation:   %d", mode_displayed[MODE_DEV], modes[MODE_DEV]);
            lcd_putsxy(0,lcd_char_height*4,buf);
 
            snprintf(buf, sizeof(buf), "%cVol Dist:    %s", mode_displayed[MODE_VOLD],dist_names[modes[MODE_VOLD]]);
            lcd_putsxy(0,lcd_char_height*5,buf);
 
            snprintf(buf, sizeof(buf), "%cBass Dist:   %s", mode_displayed[MODE_BASD],dist_names[modes[MODE_BASD]]);
            lcd_putsxy(0,lcd_char_height*6,buf);
 
            snprintf(buf, sizeof(buf), "%cTreble Dist: %s", mode_displayed[MODE_TRBD],dist_names[modes[MODE_TRBD]]);
            lcd_putsxy(0,lcd_char_height*7,buf);
 
            lcd_update();
            }
 
        int audio_stat = audio_status();
 
        /* Get Button Input */
        button = button_get(false);
 
        /* Determine which key was pressed */
        switch(button)
        {
            case BUTTON_UP:
                input_selected--;
                if(input_selected < 0) { input_selected = MAX_MODES-1; }
                break;
            case BUTTON_DOWN:
                input_selected++;
                if(input_selected > MAX_MODES-1) { input_selected = 0; }
                break;
            case BUTTON_LEFT:
                modes[input_selected]--;
                break;
            case BUTTON_RIGHT:
                modes[input_selected]++;
                break;
            case BUTTON_OFF:
                if(audio_stat & AUDIO_STATUS_RECORD) { audio_stop(); }
                else { done = true; }
                break;
            case BUTTON_PLAY:
                /* Reset defaults */
                modes[MODE_GAIN] = DEFAULT_GAIN;
                modes[MODE_VOL]  = DEFAULT_VOL ;
                modes[MODE_BASS] = DEFAULT_BASS;
                modes[MODE_TREB] = DEFAULT_TREB;
                modes[MODE_PRD]  = DEFAULT_PRD ;
                modes[MODE_RPRD] = DEFAULT_RPRD;
                modes[MODE_DEV]  = DEFAULT_DEV ;
                modes[MODE_VOLD] = DEFAULT_VOLD;
                modes[MODE_BASD] = DEFAULT_BASD;
                modes[MODE_TRBD] = DEFAULT_TRBD;
                step_position = 0;
                for(i=0;i<MAX_DIST_MODES;i++) { dist_value[i] = 0; }
                break;
            case BUTTON_F3:
                if(debug) { debug = false; }
                else { debug = true; }
                break;
            case SYS_USB_CONNECTED:
                default_event_handler(SYS_USB_CONNECTED);
                break;
            default:
                break;
            }
 
        /* Distortion Mode Processing */
 
        step_position++;    /* Step counts the position in each cycle */
        if(step_position > MAX_STEPS) { step_position = 0; }  /* Start a new wave */
 
        /* Volume Distortion Mode */
        dist_value[MODE_VOL]  = dist_wave(step_position, modes[MODE_VOLD], modes,  dist_value[MODE_VOL]);
 
        /* Bass Distortion Mode */
        dist_value[MODE_BASS] = dist_wave(step_position, modes[MODE_BASD], modes, dist_value[MODE_BASS]);
 
        /* Treble Distortion Mode */
        dist_value[MODE_TREB] = dist_wave(step_position, modes[MODE_TRBD], modes, dist_value[MODE_TREB]);
 
        /* Sleep until next step */
        if(modes[MODE_RPRD] > 0)
        {
            /* Rand sleep length is enabled */
            sleep(modes[MODE_PRD] + (rand() % modes[MODE_RPRD]));
            }
        else
        {
            /* Rand sleep length not enabled */
            sleep(modes[MODE_PRD]);
            }
 
        if(audio_stat & AUDIO_STATUS_ERROR) { done = true; }
        }
 
#if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR)
    ata_set_led_enabled(false);
#endif
 
    /*** End ***/
 
    /* these are needed to perform a safe exit */
    if(audio_status() & AUDIO_STATUS_ERROR) { audio_error_clear(); }
    audio_init_playback();
    sound_settings_apply();
    reload_directory();
 
    return(0);
    }
 
/******************************************************************************/
/* Distortion Wave Functions
 *
 * This function creates different types of distortion which will be applied to the sound
 */
int dist_wave(unsigned char step, unsigned char mode, unsigned short modes[], short distval)
{
    /* Variables */
    static unsigned char phase_shift = 0;
 
    /* Main */
    switch(mode)  /* which type of distortion should we use? */
    {
        case DIST_MODE_NONE:
            /* Set distortion to zero */
            distval = 0;
            break;
        case DIST_MODE_SAW:
            /* Stepping sawtooth waveform, (-DEV to +DEV) */
            distval = (modes[MODE_DEV] * step / MAX_STEPS) - (modes[MODE_DEV] / 2);
            break;
        case DIST_MODE_TRI:
            /* Triangle waveform, (-DEV to +DEV back to -DEV)*/
            if(step <= (MAX_STEPS >> 1))
            {
                /* lower half of cycle */
                distval = (2 * modes[MODE_DEV] / MAX_STEPS * step) - (modes[MODE_DEV] / 2);
                }
            else
            {
                /* upper half of cycle */
                distval = ((-2 * MAX_STEPS * step) / modes[MODE_DEV]) + ((3 * modes[MODE_DEV]) / 2);
                }
            break;
        case DIST_MODE_SIN:
            /* Sin waveform, (DEV / 2 * sin(step) */
            distval = ((double)((modes[MODE_DEV]) / 2) * sin(2.0 * M_PI * (double)(step) / (double)(MAX_STEPS)));
            break;
        case DIST_MODE_SQR:
            /* Square waveform, (+DEV to 0) */
            if(step > (MAX_STEPS >> 1))
            {
                /* lower half of cycle */
                distval = (modes[MODE_DEV] >> 1);
                }
            else
            {
                /* upper half of cycle */
                distval = -1 * (modes[MODE_DEV] >> 1);
                }
            break;
        case DIST_MODE_RAND:
            /* Random noise, (+1/2(DEV) to -1/2(DEV) */
            distval = ((rand() % modes[MODE_DEV]) - (modes[MODE_DEV] >> 1));
            break;
        case DIST_MODE_RANDTRI:
            /* Random phase triangle waveform, each phase starts at a random point (x to +DEV to -DEV to x) */
            if(step == 0) { phase_shift = rand() % (MAX_STEPS >> 1); }
            if(((step + phase_shift) % 16) < (MAX_STEPS >> 1))
            {
                /* lower half of cycle */
                distval = (2 * modes[MODE_DEV] / MAX_STEPS * ((step + phase_shift) % MAX_STEPS)) - (modes[MODE_DEV] / 2);
                }
            else
            {
                /* upper half of cycle */
                distval = ((-2 * MAX_STEPS * ((step + phase_shift) % MAX_STEPS)) / modes[MODE_DEV]) + ((3 * modes[MODE_DEV]) / 2);
                }
            break;
        case DIST_MODE_RANDSIN:
            /* Random phase sin waveform, each phase starts at a random point (DEV / 2 * sin(x)) */
            if(step == 0) { phase_shift = rand() % (MAX_STEPS >> 1); }
            distval = ((double)((modes[MODE_DEV]) / 2) * sin(2.0 * M_PI * (double)(((step + phase_shift) % MAX_STEPS)) / (double)(MAX_STEPS)));
            break;
        default:
            distval = 0;
            break;
        }
 
    /* End */
    return(distval);
    }
/var/www/sites/dokuwiki-2011-05-25a/data/pages/projects/devry/devms.c.txt · Last modified: 2009/04/11 22:23 (external edit)
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki