Music Visualizer

Dependencies:   mbed SDFileSystem NeoStrip PinDetect

main.cpp

Committer:
spatel465
Date:
2020-04-30
Revision:
6:2f0706de9553
Parent:
5:b6f462ece58f
Child:
8:fa37292cf52c

File content as of revision 6:2f0706de9553:

#include "mbed.h"
#include "PinDetect.h"
#include "NeoStrip.h"
#include "SDFileSystem.h"
#include "wave_player.h"
#include "rtos.h"
#include <string>
#include <vector>

# define MAX_FILE 30

#define N 40
NeoStrip strip(p21, N);

//BusOut myleds(LED1,LED2,LED3,LED4);
DigitalOut myled(LED1);

DigitalIn b2(p29, PullUp);
Serial pc(USBTX, USBRX);
SDFileSystem sd(p5, p6, p7, p8, "sd");
Ticker sampletick;
AnalogOut speaker(p18);                  // Speaker (pin)
wave_player waver(&speaker);
Serial bt(p28, p27);      // Bluetooth
DigitalOut mute(p29);          // mute pin (low for shutdown)

PwmOut spk(p24);

Thread thread1;
Thread thread2;
Thread thread3;
Mutex sd_mtx;
volatile int src = 1;  // 0 for Mic, 1 for SD card

vector<string> filenames;               // list of files in sd card
volatile int cur_song = 1;

void read_file_names(char *dir) {
    DIR *dp;
    struct dirent *dirp;
    dp = opendir(dir);
    while ((dirp = readdir(dp)) != NULL) {
        filenames.push_back(string(dirp->d_name));
    }
    closedir(dp);
}

class microphone
{
public :
    microphone(PinName pin);
    float read();
    operator float ();
private :
    AnalogIn _pin;
};
microphone::microphone (PinName pin):
    _pin(pin)
{
}
float microphone::read()
{
    return _pin.read();
}
inline microphone::operator float ()
{
    return _pin.read();
}
 
microphone mymicrophone(p16);

uint8_t r = (uint8_t)0;
uint8_t g = (uint8_t)128;
uint8_t b = (uint8_t)0;

int red, green, blue;
 
// fancy function to make rainbow colors on LEDs
int hueToRGB(float h)
{
    float r, g, b;
    if (h > 360)
        h -= 360;
    if (h < 0)
        h += 360;
    int i = (int)(h / 60.0);
    float f = (h / 60.0) - i;
    float q = 1 - f;
    
    switch (i % 6)
    {
        case 0: r = 1; g = f; b = 0; break;
        case 1: r = q; g = 1; b = 0; break;
        case 2: r = 0; g = 1; b = f; break;
        case 3: r = 0; g = q; b = 1; break;
        case 4: r = f; g = 0; b = 1; break;
        case 5: r = 1; g = 0; b = q; break;
        default: r = 0; g = 0; b = 0; break;
    }
    
    // scale to integers and return the packed value
    uint8_t R = (uint8_t)(r * 255);
    uint8_t G = (uint8_t)(g * 255);
    uint8_t B = (uint8_t)(b * 255);

    return (R << 16) | (G << 8) | B;
}

// convert float values to LED otuput for soundtest array
void float2LED(float value){
    float fnumLED = abs((value - 0.5)/3.3)*100; // can mess with this scaling for better LED output
    int numLED = (int)fnumLED;
    if (numLED > 8) numLED = 8;
    
    static float dh = 360.0 / 5;
    static float x = 0;
    
    for(int i = 0; i < numLED; i++){
        int c = hueToRGB((dh * i) - x);
        strip.setPixel(i, c);
        strip.setPixel(i + 8, c);
        strip.setPixel(i + 16, c);
        strip.setPixel(i + 24, c);
        strip.setPixel(i + 32, c);
        }
    for(int i = numLED; i < 8; i++){
        strip.setPixel(i, 0x000000);
        strip.setPixel(i + 8, 0x000000);
        strip.setPixel(i + 16, 0x000000);
        strip.setPixel(i + 24, 0x000000);
        strip.setPixel(i + 32, 0x000000);
        
        // old setup for 5 rows of 8 LEDs
        //strip.setPixel(i + i * 7, 0x000000);
//        strip.setPixel(i + 1 + i * 7, 0x000000);
//        strip.setPixel(i + 2 + i * 7, 0x000000);
//        strip.setPixel(i + 3 + i * 7, 0x000000);
//        strip.setPixel(i + 4 + i * 7, 0x000000);
//        strip.setPixel(i + 5 + i * 7, 0x000000);
//        strip.setPixel(i + 6 + i * 7, 0x000000);
//        strip.setPixel(i + 7 + i * 7, 0x000000);
        }
    x += 1;
    if (x > 360)
        x = 0;
}

// same thing but for the mic
void mic2LED(int mic){
    static float dh = 360.0 / 5;
    static float x = 0;
    
    int numLED = 0;
    if(mic == 0) numLED = 0;
    else if(mic == 1) numLED = 1;
    else if(mic == 2) numLED = 2;
    else if(mic == 3) numLED = 3;
    else if(mic == 4) numLED = 4;
    else if(mic == 5) numLED = 5;
    else if(mic == 6) numLED = 6;
    else if(mic == 7) numLED = 7;
    else if(mic == 8) numLED = 8;
    
    for(int i = 0; i < numLED; i++){
        int c = hueToRGB((dh * i) - x);
        strip.setPixel(i, c);
        strip.setPixel(i + 8, c);
        strip.setPixel(i + 16, c);
        strip.setPixel(i + 24, c);
        strip.setPixel(i + 32, c);
        }
    for(int i = numLED; i < 8; i++){
        strip.setPixel(i, 0x000000);
        strip.setPixel(i + 8, 0x000000);
        strip.setPixel(i + 16, 0x000000);
        strip.setPixel(i + 24, 0x000000);
        strip.setPixel(i + 32, 0x000000);
        }
    x += 1;
    if (x > 360)
        x = 0; 
}

 
void sound_thread() {
    FILE *wave_file;
    printf("\n\n\nHello, wave world!\n");
    string songstr = "/sd/songs/" + filenames[cur_song];
    printf("%s", songstr.c_str());
    wave_file=fopen(songstr.c_str(),"r");
    printf("file opened\n");
    waver.play(wave_file);
    fclose(wave_file);
    Thread::yield();
}
    

    
unsigned short max_range = 0xFFFF;
// function that calls above functions
void patternSound(){
    //for(int i = 0; i < 60; i++){
        float sample;
        float average = 0.67/3.3;//initial DC bias level
        
        int buffer[20];
        
        while(1){
            if (src) {
            // this part works for DAC PCM output //
            float test = (float)waver.dac_data/max_range;
            pc.printf("--%f", abs((test - 0.5)/3.3));
            float2LED(test);
            strip.write();
            }
            //------------------------------------//
            else {
            //microphone setup //
            int centervalue;
            for(int i = 0; i < 20; i++){
                sample = mymicrophone;
                //subtract 0.67V DC bias - but it varies quite a bit after loud or long sounds
                average = 0.9999*average + 0.0001*sample;//try to slowly auto adjust the DC bias level
                speaker = 0.5 +((sample - average)*33.0);//scale up to 0.0 to 1.0 for speaker output
                
                int micvalue = int(abs((sample - average)*300.0));
                //pc.printf("-%d-", micvalue); //scale to around 15 for LEDs
                
                if(i == 1){
                    centervalue = micvalue;
                }
                buffer[i] = micvalue;
                if(i > 10){
                    if(micvalue == buffer[1] && micvalue == buffer[2] && micvalue == buffer[3] &&
                        micvalue == buffer[4] && micvalue == buffer[5] && micvalue == buffer[6] && 
                        micvalue == buffer[7] && micvalue == buffer[8] && micvalue == buffer[9]){
                              centervalue = buffer[1];
                              //pc.printf("-%d-", centervalue);
                              }
                    }
                int offset = micvalue-centervalue;
                //pc.printf(" %d ", offset);
                //myleds = micvalue;
                mic2LED(2+offset);
                wait(1.0/4000.0);
                }
               ////////////////////////////////////////////////////////
            strip.write();
            Thread::wait(10);
            }
        }
}

void bt_thread() {
    char bnum = 0;
    char bhit = 0;
    while(1) {
        if (bt.readable()) {
            if (bt.getc()=='!') {
                if (bt.getc()=='B') { //button data
                    bnum = bt.getc(); //button number
                    bhit = bt.getc(); //1 = hit, 0 = release
                    if (bhit == '1') {
                        switch (bnum) {
                            case '1':   // Button 1 for play/pause
                                if (waver.get_play_state() == 1) {
                                    waver.set_play_state(0);
                                    thread2.terminate();
                                    mute = 0;
                                } else if (waver.get_play_state() == 0) {
                                    waver.set_play_state(1);
                                    thread2.start(sound_thread);
                                    mute = 1;
                                }
                                break;
                            case '2':   // Button 2 for mute/unmute
                                mute = !mute;
                                break;
                            case '3':   // Button 3 to switch between mic/sd
                                if (sd_mtx.trylock()) {
                                    sd_mtx.lock();
                                    src = src ? 0 : 1;
                                    if (src) {
                                        waver.set_play_state(1);
                                        thread2.start(sound_thread);
                                        mute = 1;
                                    } else {
                                        waver.set_play_state(0);
                                        while (thread2.get_state() == Thread::Running) {
                                            Thread::yield();
                                        }
                                        thread2.terminate();
                                        mute = 0;
                                    }
                                    sd_mtx.unlock();
                                    Thread::wait(100);
                                }
                                break;
                            case '7':   // Left arrow for previous
                                if (sd_mtx.trylock()) {
                                    sd_mtx.lock();
                                    waver.set_play_state(0);
                                    if (cur_song > 0) {
                                        --cur_song;
                                    }
                                    while (thread2.get_state() == Thread::Running) {
                                        Thread::yield();
                                    }
                                    thread2.terminate();
                                    thread2.start(sound_thread);
                                    waver.set_play_state(1);
                                    sd_mtx.unlock();
                                }
                                break;
                            case '8':   // Right arrow for skip
                                if (sd_mtx.trylock()) {
                                    sd_mtx.lock();
                                    waver.set_play_state(0);
                                    if (cur_song < filenames.size() - 1) {
                                        ++cur_song;
                                    }
                                    while (thread2.get_state() == Thread::Running) {
                                        Thread::yield();
                                    }
                                    thread2.terminate();
                                    thread2.start(sound_thread);
                                    waver.set_play_state(1);
                                    sd_mtx.unlock();
                                }
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
        }
        Thread::wait(100);
    }
}

int main() {
    read_file_names("/sd/songs");

    strip.setBrightness(0.05);
    
    mute = 1;
        
    thread1.start(bt_thread);
    thread2.start(sound_thread);
    thread3.start(patternSound);
    
    while(1){
        myled = !myled;
        Thread::wait(100);
    }
}