/*  public void saveToExternal(WinDataClass wd){
     *
     *   string dest = Application.persistentDataPath + "/winData.dat";
     *   FileStream file;
     *   //string jsonStr = JsonUtility.ToJson(player);
     *
     *   if(File.Exists(dest)){
     *       file = File.OpenWrite(dest);
     *   }else{
     *       file = File.Create(dest);
     *   }
     *
     *   BinaryFormatter bf = new BinaryFormatter();
     *   bf.Serialize(file, wd);
     *   file.Close();
     * } */

    // handles updating the player data after a win
    // calculating the grade, etc.
    public void handleGameWin()
    {
        print("handleGameWin()");
        //decimal moneyEarnedDecimal = (decimal)(Math.Sqrt(_playerScore) * (_playerNotesHit/totalNotes) + _playerMaxCombo)/100;
        //decimal expEarnedDecimal = (decimal)(Math.Sqrt(_playerScore)) * (_playerNotesHit/totalNotes) + (_playerMaxCombo == 1 ? 0 : _playerMaxCombo);


        WinDataClass winData         = new WinDataClass(0, 0, 0, 0, 0, 0, "");
        string       calculatedGrade = "";
        float        notePercentage  = (float)((decimal)_playerNotesHit / (decimal)totalNotes);

        if (notePercentage < 0.5)
        {
            calculatedGrade = "D";
        }
        else if (notePercentage >= 0.5 && notePercentage < 0.6)
        {
            calculatedGrade = "C";
        }
        else if (notePercentage >= 0.6 && notePercentage < 0.7)
        {
            calculatedGrade = "B";
        }
        else if (notePercentage >= 0.7 && notePercentage < 0.8)
        {
            calculatedGrade = "A";
        }
        else if (notePercentage >= 0.8 && notePercentage < 0.9)
        {
            calculatedGrade = "S";
        }
        else if (notePercentage >= 0.9 && notePercentage < 1)
        {
            calculatedGrade = "SS";
        }
        else
        {
            calculatedGrade = "ACE";
        }


        winData.score         = _playerScore;
        winData.maxCombo      = _playerMaxCombo;
        winData.notesHit      = _playerNotesHit;
        winData.mapTotalNotes = totalNotes;                                                                                                                                                 // can calculate the percentage using this and above
        winData.moneyEarned   = (int)Math.Round((Math.Sqrt(_playerScore) * (float)((decimal)_playerNotesHit / (decimal)totalNotes) + _playerMaxCombo) / 100.0);                             // round money earned to closest integer
        winData.expEarned     = (float)Math.Round(((Math.Sqrt(_playerScore)) * (float)((decimal)_playerNotesHit / (decimal)totalNotes) + (_playerMaxCombo == 1 ? 0 : _playerMaxCombo)), 2); // round exp to 2 digits
        winData.grade         = calculatedGrade;

        print("big equation thing: " + Math.Round(((Math.Sqrt(_playerScore) * (float)((decimal)_playerNotesHit / (decimal)totalNotes) + _playerMaxCombo) / 100.0), 2));

        /*
         * print("square root: " + (float)(Math.Sqrt(_playerScore)));
         * print("percentage: " + (float)((_playerNotesHit/totalNotes)*1.0));
         * print("winData.moneyEarned: " + winData.moneyEarned);
         * print("winData.expEarned: " + winData.expEarned); */

        //scoreboard
        beatMap.addWin(winData);
        beatMap.save(Application.persistentDataPath);

        WinDataClassHelper.saveToExternal(winData);

        _gameState = GameState.win;
        //SceneManager.LoadScene("VictoryRoyaleScene");
    }
示例#2
0
    // float[] getCombinedSamplesWeb (ref float[] samples) {
    // }

    //The B(eat) G(enerating) A(lgorithim)
    //Background thread to create the beatmap
    void algorithim()
    {
        Debug.Log("algo");
        //float[] samples = //getCombinedSamples(ref song_info.samples, song_info.sampleCount, song_info.channels);

        float[] samples = song_info.samples;

        Debug.Log("Song samples coverted to mono");

        int finalArraySize = song_info.sampleCount / settings.n_bins;

        Debug.Log(finalArraySize);
        output.fftData         = new float[finalArraySize][];
        output.flux            = new float[finalArraySize];
        output.flux2           = new float[finalArraySize];
        output.peaks           = new float[finalArraySize];
        output.peaks2          = new float[finalArraySize];
        output.threshold       = new float[finalArraySize];
        output.peakThreshold   = new float[finalArraySize];
        output.drifts          = new float[finalArraySize];
        output.flySectionIndex = 0;
        FFTProvider fftProvider = new DSPLibFFTProvider(settings.n_bins);
        WINDOW_TYPE fftWindow   = WINDOW_TYPE.Hamming;

        Debug.Log("done allocating large amount of ram");

        //perform fft using N_BINS at a time
        for (int i = 0; i < finalArraySize; i++)
        {
            float[] currSamples = new float[settings.n_bins];
            int     startIndex  = (i * settings.n_bins);
            //Grab the current sample (length N_BINS) from the samples data
            for (int j = startIndex; j < startIndex + settings.n_bins; j++)
            {
                currSamples[j - startIndex] = samples[j];
            }

            Debug.Log("doFFT");
            output.fftData[i] = fftProvider.doFFT(currSamples, fftWindow);

            if (i != 0)
            {
                //Compute the spectral flux for the current spectrum
                float flux = 0;
                for (int j = 0; j < output.fftData[i].Length; j++)
                {
                    float currFlux = (output.fftData[i][j] - output.fftData[i - 1][j]);
                    //we only want 'rising' spectral flux - since we are detecting beat onset therefore we only care about rise in power
                    if (currFlux > 0)
                    {
                        flux += currFlux;
                    }
                }
                output.flux[i] = flux;
            }
            else
            {
                output.flux[0] = 0;
            }
        }

        //define a window size for the threshold. THRESHOLD_TIME is the length in time that the window should be.
        int thresholdWindowSize = Mathf.FloorToInt((settings.threshold_time / song_info.sampleLength) / settings.n_bins);

        Debug.Log("threshold: ");
        Debug.Log(thresholdWindowSize);

        //Compute threshold for each flux value
        for (int i = 0; i < output.flux.Length; i++)
        {
            float avg   = 0;
            float count = 0;
            for (int j = (i - thresholdWindowSize); j < (i + thresholdWindowSize); j++)
            {
                if (j < 0 || j >= output.flux.Length)
                {
                    continue;                                   //todo should be optimized
                }
                avg   += output.flux[j];
                count += 1;
            }
            if (count > 0)
            {
                output.threshold[i] = (avg / count) * settings.threshold_multiplier;
            }
            else
            {
                output.threshold[i] = 0f;
            }
        }

        //using the computed threshold, discard any flux values that are below/at the threshold (most likely not a beat as it is below avg)
        for (int i = 0; i < output.flux.Length; i++)
        {
            if (output.flux[i] <= output.threshold[i])
            {
                output.flux2[i] = 0f;
            }
            else
            {
                output.flux2[i] = output.flux[i]; //subtract avg so we see only the peak
            }
        }

        //Check for peaks: If curr value > next value this is a peak

        for (int i = 0; i < output.flux2.Length - 1; i++)
        {
            if (output.flux2[i] > output.flux2[i + 1])
            {
                output.peaks[i]    = output.flux2[i]; //Beat Detected
                output.totalPeaks += 1;
            }
            else
            {
                output.peaks[i] = 0f;
            }
        }

        //avg # of beats per second... multiply by 60 to get bpm
        output.totalPeaksOverTime = output.totalPeaks / song_info.length;

        Debug.Log("BPM: ");
        Debug.Log(output.totalPeaksOverTime * 60);

        //fly detection

        //define a window size for the threshold. THRESHOLD_TIME is the length in time that the window should be. for now use drift threshold time
        int flyThresholdWindowSize = Mathf.FloorToInt((settings.fly_threshold_time / song_info.sampleLength) / settings.n_bins) / 2;

        Debug.Log("threshold3: ");
        Debug.Log(flyThresholdWindowSize);

        //only look at the song between 30% and 70% duration,
        //and only find largest value.

        float largestDelta = 0;
        int   indexLargest = 0;

        Debug.Log("Detect fly");
        Debug.Log(Mathf.FloorToInt(.30f * output.peaks.Length));
        Debug.Log(Mathf.FloorToInt(.70f * output.peaks.Length));

        for (int i = Mathf.FloorToInt(.30f * output.peaks.Length); i < Mathf.FloorToInt(.70f * output.peaks.Length); i++)
        {
            float avgL   = 0;
            float avgR   = 0;
            float countL = 0;
            float countR = 0;

            for (int j = (i - flyThresholdWindowSize); j < (i + flyThresholdWindowSize); j++)
            {
                if (j < 0 || j >= output.peaks.Length)
                {
                    continue;                                    //todo should be optimized
                }
                if (j < i)
                {
                    avgL   += output.peaks[j];
                    countL += 1;
                }
                else
                {
                    avgR   += output.peaks[j];
                    countR += 1;
                }
            }
            if (countL > 0 && countR > 0)
            {
                float avg = (avgL / countL) - (avgR / countR); //we are looking for the biggest difference from left to right
                if (avg > largestDelta)
                {
                    largestDelta = avg;
                    indexLargest = i;
                }
            }
        }

        output.flySectionIndex = indexLargest;

        Debug.Log("Fly section: ");
        Debug.Log(output.flySectionIndex);

        //end fly detection

        //drift detection

        //define a window size for the threshold. THRESHOLD_TIME is the length in time that the window should be.
        int driftThresholdWindowSize = Mathf.FloorToInt((settings.drift_threshold_time / song_info.sampleLength) / settings.n_bins) / 2;

        Debug.Log("threshold2: ");
        Debug.Log(driftThresholdWindowSize);

        //Compute a threshold on avg # of peaks at a given time
        for (int i = 0; i < output.peaks.Length; i++)
        {
            float avg   = 0;
            float count = 0;
            for (int j = (i - driftThresholdWindowSize); j < (i + driftThresholdWindowSize); j++)
            {
                if (j < 0 || j >= output.peaks.Length)
                {
                    continue;                                    //todo should be optimized
                }
                avg   += output.peaks[j];
                count += 1;
            }
            if (count > 0)
            {
                output.peakThreshold[i] = (avg / count);
            }
            else
            {
                output.peakThreshold[i] = 0f;
            }
        }

        //select amount_drift_sections from output.peakThreshold, ensuring that each drift section is min_time_between_drift apart
        //remove all duplicates / close values next to a value, then store remaning values as a GreatestValueElement in a arraylist, then sort the list.

        List <GreatestValueElement> greatestValues = new List <GreatestValueElement>();

        Debug.Log("Start greatestvalues");
        int offset = 1;

        for (int i = 0; i < output.peakThreshold.Length; i += offset)
        {
            offset = 1;
            if ((i - driftThresholdWindowSize) <= 0 || (i + driftThresholdWindowSize) >= output.peakThreshold.Length) //throw out values near beginning and near end
            {
                continue;
            }
            while (((i + offset) < output.peakThreshold.Length) && Math.Abs(output.peakThreshold[i] - output.peakThreshold[i + offset]) <= delta)
            {
                output.peakThreshold[i + offset] = 0;
                offset += 1;
            }
            GreatestValueElement elem = new GreatestValueElement(i, output.peakThreshold[i]);
            greatestValues.Add(elem);
        }

        Debug.Log("Sort greatestvalues");

        //todo debug this...
        try {
            greatestValues.Sort((x, y) => y.value.CompareTo(x.value));
        }
        catch (Exception e) {
            Debug.Log("Could not sort greatestValues!");
            Debug.Log(e.ToString());
        }

        Debug.Log("Song length:");
        Debug.Log(song_info.length);

        int minLengthBetweenDrift = Mathf.FloorToInt((settings.min_drift_seperation_time / song_info.sampleLength) / settings.n_bins);
        int totalAllowableDrifts  = Mathf.FloorToInt(settings.drifts_per_minute * Mathf.FloorToInt(song_info.length / 60f));
        int warmUpTimeLength      = Mathf.FloorToInt((settings.warm_up_time / song_info.sampleLength) / settings.n_bins);

        Debug.Log("drifts per minute:");
        Debug.Log(settings.drifts_per_minute);

        Debug.Log("Drift sections: ");
        Debug.Log(totalAllowableDrifts);

        Debug.Log("Min length between drifts: ");
        Debug.Log(minLengthBetweenDrift);

        //select elements and make sure they are min_time_between_drift apart
        int numSelected = 0;
        List <GreatestValueElement> addedValues = new List <GreatestValueElement>();
        bool first = true;

        foreach (GreatestValueElement elem in greatestValues)
        {
            if (numSelected >= totalAllowableDrifts)
            {
                break;
            }
            if (first)
            {
                int offSetIndex = Math.Max(elem.index - driftThresholdWindowSize, 0);
                if (offSetIndex == 0)
                {
                    continue;
                }
                if (offSetIndex - warmUpTimeLength <= 0)
                {
                    continue;
                }
                output.drifts[offSetIndex] = elem.value;
                numSelected = 1;
                first       = false;
                addedValues.Add(elem);
            }
            else
            {
                bool flag = false;
                //We need to check if this elem is properly spaced at least min_time_between_drift apart from other drifts
                //And that the elem is not in the middle of a <fly> section or <time_after_fly> section
                foreach (GreatestValueElement added in addedValues)
                {
                    if (Math.Abs(elem.index - added.index) <= minLengthBetweenDrift ||
                        Math.Abs(elem.index - output.flySectionIndex) <= (flyThresholdWindowSize * 2.2))
                    {
                        flag = true;
                        break;
                    }
                }
                if (!flag)
                {
                    int offSetIndex = Math.Max(elem.index - driftThresholdWindowSize, 0);
                    if (offSetIndex == 0)
                    {
                        continue;
                    }
                    if (offSetIndex - warmUpTimeLength <= 0)
                    {
                        continue;
                    }
                    output.drifts[offSetIndex] = elem.value;
                    numSelected += 1;
                    addedValues.Add(elem);
                }
            }
        }

        //end drift detection

        //Filter peaks to allowable min_time_between_peaks
        //Todo this is a bit naive should probably select highest peak or something (but will work for now)
        //int minLengthBetweenPeaks = Mathf.FloorToInt(Mathf.FloorToInt((settings.min_peak_seperation_time / sampleLength) / settings.n_bins) / 2);
        if (settings.min_peak_seperation_time > 0)
        {
            int minLengthBetweenPeaks = Mathf.FloorToInt((settings.min_peak_seperation_time / song_info.sampleLength) / settings.n_bins);
            for (int i = 0; i < output.peaks.Length; i++)
            {
                if (output.peaks[i] > 0)
                {
                    output.peaks2[i] = output.peaks[i];
                    i += minLengthBetweenPeaks - 1;
                }
            }
        }
        else
        {
            for (int i = 0; i < output.peaks.Length; i++)
            {
                output.peaks2[i] = output.peaks[i];
            }
        }

        BeatMap beatMap = makeBeatMap(driftThresholdWindowSize * 2, flyThresholdWindowSize * 2);

        beatMap.save(persistentDataPath);

        //todo deal with random stuff below
        //debug output

        Debug.Log("BGA Done");
        this.state = STATE.DONE;

        // using (StreamWriter file = new StreamWriter("output.txt"))
        // {
        //     for (int i=0; i < output.flux.Length; i++)
        //     {
        //         file.WriteLine(output.flux[i]);
        //     }
        // }
        // using (StreamWriter file = new StreamWriter("output2.txt"))
        // {
        //     for (int i = 0; i < output.threshold.Length; i++)
        //     {
        //         file.WriteLine(output.threshold[i]);
        //     }
        // }
        // using (StreamWriter file = new StreamWriter("output3.txt"))
        // {
        //     for (int i = 0; i < output.flux2.Length; i++)
        //     {
        //         file.WriteLine(output.flux2[i]);
        //     }
        // }
        // using (StreamWriter file = new StreamWriter("output4.txt"))
        // {
        //     for (int i = 0; i < output.peaks.Length; i++)
        //     {
        //         file.WriteLine(output.peaks[i]);
        //     }
        // }
        // using (StreamWriter file = new StreamWriter("output5.txt"))
        // {
        //     for (int i = 0; i < output.peaks2.Length; i++)
        //     {
        //         file.WriteLine(output.peaks2[i]);
        //     }
        // }
        // using (StreamWriter file = new StreamWriter("output6.txt"))
        // {
        //     for (int i = 0; i < output.peakThreshold.Length; i++)
        //     {
        //         file.WriteLine(output.peakThreshold[i]);
        //     }
        // }
        // using (StreamWriter file = new StreamWriter("output7.txt"))
        // {
        //     for (int i = 0; i < output.drifts.Length; i++)
        //     {
        //         file.WriteLine(output.drifts[i]);
        //     }
        // }
        // using (StreamWriter file = new StreamWriter("output8.txt"))
        // {
        //     Queue<LaneObject> laneObjects = beatMap.initLaneObjectQueue();
        //     foreach (LaneObject l in laneObjects) {
        //         file.WriteLine(l.sampleIndex + " " + l.lane + " " + l.time + " " + (l.type == LANE_OBJECT_TYPE.Beat ? "1" : "0"));
        //     }
        // }


        // Debug.Log("Output file saved");


        //frameScale = (int) (songLength / finalArraySize);
        //float sampleLength = song_info.length / (float)song_info.sampleCount;
        //Debug.Log(sampleLength);

        //Debug.Log(sampleLength * 1000);
        //Debug.Log(sampleLength * N_BINS); //length per reading

        //done = true;
    }