* data) {
+ constexpr std::size_t N = 1 << P;
+ constexpr std::size_t M = N / 2;
+ // Compute even and odd halves
+ DanielsonLanczos().apply(data);
+ DanielsonLanczos
().apply(data + M);
+ // Combine the results
+ std::complex w(1.0);
+ for (std::size_t i = 0; i < M; ++i) {
+ const std::complex temp = data[i + M] * w;
+ data[M + i] = data[i] - temp;
+ data[i] += temp;
+ w *= std::polar(1.0, -M_TAU / N);
+ }
+ }
+ };
+
+ template struct DanielsonLanczos<0, T> { static void apply(std::complex*) {} };
+
+ /** Perform FFT on data. **/
+ template void fft(std::complex* data) {
+ // Perform bit-reversal sorting of sample data.
+ constexpr std::size_t N = 1 << P;
+ std::size_t j = 0;
+ for (std::size_t i = 0; i < N; ++i) {
+ if (i < j) std::swap(data[i], data[j]);
+ std::size_t m = N / 2;
+ while (m > 1 && m <= j) { j -= m; m >>= 1; }
+ j += m;
+ }
+ // Do the actual calculation
+ DanielsonLanczos::apply(data);
+ }
+
+ /** Perform FFT on data from floating point iterator, windowing the input. **/
+ template std::vector > fft(InIt begin, Window window) {
+ std::vector > data(1 << P);
+ // Perform bit-reversal sorting of sample data.
+ constexpr std::size_t N = 1 << P;
+ std::size_t j = 0;
+ for (std::size_t i = 0; i < N; ++i) {
+ data[j] = *begin++ * window[i];
+ std::size_t m = N / 2;
+ while (m > 1 && m <= j) { j -= m; m >>= 1; }
+ j += m;
+ }
+ // Do the actual calculation
+ DanielsonLanczos::apply(&data[0]);
+ return data;
+ }
+
+ template void ifft(std::complex* data) {
+ constexpr std::size_t N = 1 << P;
+ for (std::size_t i = 0; i < N; ++i) data[i] = std::conj(data[i]); // Invert phase so that we can use FFT to do IFFT
+ fft(data);
+ constexpr std::complex scale(1.0/N, 0.0);
+ for (std::size_t i = 0; i < N; ++i) data[i] = scale * std::conj(data[i]); // Invert back, and apply IFFT scaling
+ }
+
+}
diff --git a/PitchTracker/performous/libda/sample.hpp b/PitchTracker/performous/libda/sample.hpp
new file mode 100644
index 00000000..a09bbcb6
--- /dev/null
+++ b/PitchTracker/performous/libda/sample.hpp
@@ -0,0 +1,82 @@
+#pragma once
+
+#include
+#include "../compatibility.h"
+
+/**
+ * @file sample.hpp Sample format definition and format conversions.
+ */
+
+namespace da {
+
+ using std::round;
+
+ // Should be a floating-point type
+ typedef float sample_t;
+
+ // A helper function for clamping a value to a certain range
+ template T clamp(T val, T min, T max) {
+ if (val < min) val = min;
+ if (val > max) val = max;
+ return val;
+ }
+
+ constexpr sample_t max_s16(32767), min_s16 = -max_s16 - sample_t(1);
+ constexpr sample_t max_s24(8388607), min_s24 = -max_s24 - sample_t(1);
+ constexpr sample_t max_s32(2147483647), min_s32= -max_s32 - sample_t(1);
+ constexpr double tau(6.2831853071795864769252867665590057683943387987502116); ///< One full circle
+ constexpr double pi = tau / sample_t(2); ///< Half circle
+ constexpr double eps(1e-10); ///< Tiny positive value
+
+ /// Mathematical sinc function
+ template static inline Float msinc(Float x) { return std::abs(x) < Float(eps) ? Float(1) : std::sin(x) / x; }
+
+ /// Normalized (signal processing) sinc function
+ template static inline Float sinc(Float x) { return msinc(Float(pi) * x); }
+
+ /// Lanczos kernel of size A
+ template static inline Float lanc(Float x) {
+ return std::abs(x) < A ? sinc(x) * sinc(x / A) : Float();
+ }
+
+ // The following conversions provide lossless conversions between floats
+ // and integers. Be sure to use only these conversions or otherwise the
+ // conversions may not be lossless, due to different scaling factors being
+ // used by different libraries.
+
+ // The negative minimum integer value produces sample_t value slightly
+ // more negative than -1.0 but this is necessary in order to prevent
+ // clipping in the float-to-int conversions. Now amplitude 1.0 in floating
+ // point produces -32767 .. 32767 symmetrical non-clipping range in s16.
+
+ static inline sample_t conv_from_s16(int s) { return s / max_s16; }
+ static inline sample_t conv_from_s24(int s) { return s / max_s24; }
+ static inline sample_t conv_from_s32(int s) { return s / max_s32; }
+ // The rounding is strictly not necessary, but it greatly improves
+ // the error tolerance if any floating point calculations are done.
+ // The ugly static_casts are required to avoid warnings in MSVC.
+ static inline int conv_to_s16(sample_t s) { return clamp(static_cast(round(s * max_s16)), static_cast(min_s16), static_cast(max_s16)); }
+ static inline int conv_to_s24(sample_t s) { return clamp(static_cast(round(s * max_s24)), static_cast(min_s24), static_cast(max_s24)); }
+ static inline int conv_to_s32(sample_t s) { return static_cast(clamp(round(s * max_s32), min_s32, max_s32 )); }
+ // Non-rounding non-clamping versions are provided for very low end devices (still lossless)
+ static inline int conv_to_s16_fast(sample_t s) { return static_cast(s * max_s16); }
+ static inline int conv_to_s24_fast(sample_t s) { return static_cast(s * max_s24); }
+ static inline int conv_to_s32_fast(sample_t s) { return static_cast(s * max_s32); }
+
+ template class step_iterator: public std::iterator {
+ ValueType* m_pos;
+ std::ptrdiff_t m_step;
+ public:
+ step_iterator(ValueType* pos, std::ptrdiff_t step): m_pos(pos), m_step(step) {}
+ ValueType& operator*() { return *m_pos; }
+ step_iterator operator+(std::ptrdiff_t rhs) { return step_iterator(m_pos + m_step * rhs, m_step); }
+ step_iterator& operator++() { m_pos += m_step; return *this; }
+ step_iterator operator++(int) { step_iterator ret = *this; ++*this; return ret; }
+ bool operator!=(step_iterator const& rhs) const { return m_pos != rhs.m_pos; }
+ std::ptrdiff_t operator-(step_iterator const& rhs) const { return (m_pos - rhs.m_pos) / m_step; }
+ // TODO: more operators
+ };
+
+ typedef step_iterator sample_iterator;
+ typedef step_iterator sample_const_iterator;
+}
diff --git a/PitchTracker/performous/pitch.cc b/PitchTracker/performous/pitch.cc
new file mode 100644
index 00000000..760dc9dc
--- /dev/null
+++ b/PitchTracker/performous/pitch.cc
@@ -0,0 +1,235 @@
+#include "pitch.hh"
+
+#include "util.hh"
+#include "libda/fft.hpp"
+#include
+#include
+#include
+
+// Limit the range to avoid noise and useless computation
+static const double FFT_MINFREQ = 45.0;
+static const double FFT_MAXFREQ = 5000.0;
+
+Tone::Tone():
+ freq(0.0),
+ db(-getInf()),
+ stabledb(-getInf()),
+ age()
+{
+ for (auto& h: harmonics) h = -getInf();
+}
+
+void Tone::print() const {
+ if (age < Tone::MINAGE) return;
+ std::cout << std::fixed << std::setprecision(1) << freq << " Hz, age " << age << ", " << db << " dB:";
+ for (std::size_t i = 0; i < 8; ++i) std::cout << " " << harmonics[i];
+ std::cout << std::endl;
+}
+
+bool Tone::operator==(double f) const {
+ return std::abs(freq / f - 1.0) < 0.05;
+}
+
+Analyzer::Analyzer(double rate, std::string id, unsigned step):
+ m_step(step),
+ m_resampleFactor(1.0),
+ m_resamplePos(),
+ m_rate(rate),
+ m_id(id),
+ m_window(FFT_N),
+ m_fftLastPhase(FFT_N / 2),
+ m_peak(0.0),
+ m_oldfreq(0.0)
+{
+ if (m_step > FFT_N) throw std::logic_error("Analyzer step is larger that FFT_N (ideally it should be less than a fourth of FFT_N).");
+ // Hamming window
+ for (size_t i=0; i < FFT_N; i++) {
+ m_window[i] = static_cast(0.53836 - 0.46164 * std::cos(2.0 * M_PI * i / (FFT_N - 1)));
+ }
+}
+
+bool Analyzer::output(float* begin, float* end, double rate) {
+ constexpr unsigned a = 2;
+ const size_t size = m_passthrough.size();
+ const unsigned out = static_cast((end - begin) / 2 /* stereo */);
+ if (out == 0) return false;
+ const unsigned in = static_cast(m_resampleFactor * (m_rate / rate) * out + 2 * a /* lanczos kernel */ + 5 /* safety margin for rounding errors */);
+ float pcm[m_passthrough.capacity];
+ if(!m_passthrough.read(pcm, pcm + in + 4))
+ return false;
+ for (unsigned i = 0; i < out; ++i) {
+ double s = 0.0;
+ unsigned k = static_cast(m_resamplePos);
+ double x = m_resamplePos - k;
+ // Lanczos sampling of input at m_resamplePos
+ for (unsigned j = 0; j <= 2 * a; ++j) s += pcm[k + j] * da::lanc(x - j + a);
+ s *= 5.0;
+ begin[i * 2] += (float) s;
+ begin[i * 2 + 1] += (float) s;
+ m_resamplePos += m_resampleFactor;
+ }
+ unsigned num = static_cast(m_resamplePos);
+ m_resamplePos -= num;
+ if (size > 3000) {
+ // Reset
+ m_passthrough.pop(size - 700);
+ m_resampleFactor = 1.0;
+ } else {
+ m_passthrough.pop(num);
+ m_resampleFactor = 0.99 * m_resampleFactor + 0.01 * (size > 700 ? 1.02 : 0.98);
+ }
+ return true;
+}
+
+
+namespace {
+ struct Peak {
+ double freq;
+ double db;
+ bool harm[Tone::MAXHARM];
+ Peak(double _freq = 0.0, double _db = -getInf()):
+ freq(_freq), db(_db)
+ {
+ for (auto& h: harm) h = false;
+ }
+ void clear() {
+ freq = 0.0;
+ db = -getInf();
+ }
+ };
+
+ Peak& match(std::vector& peaks, std::size_t pos) {
+ std::size_t best = pos;
+ if (peaks[pos - 1].db > peaks[best].db) best = pos - 1;
+ if (peaks[pos + 1].db > peaks[best].db) best = pos + 1;
+ return peaks[best];
+ }
+}
+
+bool Analyzer::calcFFT() {
+ float pcm[FFT_N];
+ // Read FFT_N samples, move forward by m_step samples
+ if (!m_buf.read(pcm, pcm + FFT_N)) return false;
+ m_buf.pop(m_step);
+ // Peak level calculation of the most recent m_step samples (the rest is overlap)
+ for (float const* ptr = pcm + FFT_N - m_step; ptr != pcm + FFT_N; ++ptr) {
+ float s = *ptr;
+ float p = s * s;
+ if (p > m_peak) m_peak = p; else m_peak *= 0.999;
+ }
+ // Calculate FFT
+ m_fft = da::fft(pcm, m_window);
+ return true;
+}
+
+void Analyzer::calcTones() {
+ // Precalculated constants
+ const double freqPerBin = m_rate / FFT_N;
+ const double phaseStep = 2.0 * M_PI * m_step / FFT_N;
+ const double normCoeff = 1.0 / FFT_N;
+ const double minMagnitude = pow(10, -100.0 / 20.0) / normCoeff; // -100 dB
+ // Limit frequency range of processing
+ const size_t kMin = std::max(size_t(1), size_t(FFT_MINFREQ / freqPerBin));
+ const size_t kMax = std::min(FFT_N / 2, size_t(FFT_MAXFREQ / freqPerBin));
+ std::vector peaks(kMax + 1); // One extra to simplify loops
+ for (size_t k = 1; k <= kMax; ++k) {
+ double magnitude = std::abs(m_fft[k]);
+ double phase = std::arg(m_fft[k]);
+ // process phase difference
+ double delta = phase - m_fftLastPhase[k];
+ m_fftLastPhase[k] = static_cast(phase);
+ delta -= k * phaseStep; // subtract expected phase difference
+ delta = remainder(delta, 2.0 * M_PI); // map delta phase into +/- M_PI interval
+ delta /= phaseStep; // calculate diff from bin center frequency
+ double freq = (k + delta) * freqPerBin; // calculate the true frequency
+ if (freq > 1.0 && magnitude > minMagnitude) {
+ peaks[k].freq = freq;
+ peaks[k].db = 20.0 * log10(normCoeff * magnitude);
+ }
+ }
+ // Prefilter peaks
+ double prevdb = peaks[0].db;
+ for (size_t k = 1; k < kMax; ++k) {
+ double db = peaks[k].db;
+ if (db > prevdb) peaks[k - 1].clear();
+ if (db < prevdb) peaks[k].clear();
+ prevdb = db;
+ }
+ // Find the tones (collections of harmonics) from the array of peaks
+ tones_t tones;
+ for (size_t k = kMax - 1; k >= kMin; --k) {
+ if (peaks[k].db < -70.0) continue;
+ // Find the best divider for getting the fundamental from peaks[k]
+ std::size_t bestDiv = 1;
+ int bestScore = 0;
+ for (std::size_t div = 2; div <= Tone::MAXHARM && k / div > 1; ++div) {
+ double freq = peaks[k].freq / div; // Fundamental
+ int score = 0;
+ for (std::size_t n = 1; n < div && n < 8; ++n) {
+ Peak& p = match(peaks, k * n / div);
+ --score;
+ if (p.db < -90.0 || std::abs(p.freq / n / freq - 1.0) > .03) continue;
+ if (n == 1) score += 4; // Extra for fundamental
+ score += 2;
+ }
+ if (score > bestScore) {
+ bestScore = score;
+ bestDiv = div;
+ }
+ }
+ // Construct a Tone by combining the fundamental frequency (freq) and all harmonics
+ Tone t;
+ std::size_t count = 0;
+ double freq = peaks[k].freq / bestDiv;
+ t.db = peaks[k].db;
+ for (std::size_t n = 1; n <= bestDiv; ++n) {
+ // Find the peak for n'th harmonic
+ Peak& p = match(peaks, k * n / bestDiv);
+ if (std::abs(p.freq / n / freq - 1.0) > .03) continue; // Does it match the fundamental freq?
+ if (p.db > t.db - 10.0) {
+ t.db = std::max(t.db, p.db);
+ ++count;
+ t.freq += p.freq / n;
+ }
+ t.harmonics[n - 1] = p.db;
+ p.clear();
+ }
+ t.freq /= count;
+ // If the tone seems strong enough, add it (-3 dB compensation for each harmonic)
+ if (t.db > -50.0 - 3.0 * count) {
+ t.stabledb = t.db;
+ tones.push_back(t);
+ }
+ }
+ mergeWithOld(tones);
+ m_tones.swap(tones);
+}
+
+void Analyzer::mergeWithOld(tones_t& tones) const {
+ tones.sort();
+ auto it = tones.begin();
+ // Iterate over old tones
+ for (auto const& old: m_tones) {
+ // Try to find a matching new tone
+ while (it != tones.end() && *it < old) ++it;
+ // If match found
+ if (it != tones.end() && *it == old) {
+ // Merge the old tone into the new tone
+ it->age = old.age + 1;
+ it->stabledb = 0.8 * old.stabledb + 0.2 * it->db;
+ it->freq = 0.5 * old.freq + 0.5 * it->freq;
+ } else if (old.db > -80.0) {
+ // Insert a decayed version of the old tone into new tones
+ Tone& t = *tones.insert(it, old);
+ t.db -= 5.0;
+ t.stabledb -= 0.1;
+ }
+ }
+}
+
+void Analyzer::process() {
+ // Try calculating FFT and calculate tones until no more data in input buffer
+ while (calcFFT()) calcTones();
+}
+
+
diff --git a/PitchTracker/performous/pitch.hh b/PitchTracker/performous/pitch.hh
new file mode 100644
index 00000000..1108e0b9
--- /dev/null
+++ b/PitchTracker/performous/pitch.hh
@@ -0,0 +1,131 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include "../compatibility.h"
+
+/// struct to represent tones
+struct Tone {
+ static const std::size_t MAXHARM = 48; ///< The maximum number of harmonics tracked
+ static const std::size_t MINAGE = 2; ///< The minimum age required for a tone to be output
+ double freq; ///< Frequency (Hz)
+ double db; ///< Level (dB)
+ double stabledb; ///< Stable level, useful for graphics rendering
+ double harmonics[MAXHARM]; ///< Harmonics' levels
+ std::size_t age; ///< How many times the tone has been detected in row
+ Tone();
+ void print() const; ///< Prints Tone to std::cout
+ bool operator==(double f) const; ///< Compare for rough frequency match
+ /// Less-than compare by levels (instead of frequencies like operator< does)
+ static bool dbCompare(Tone const& l, Tone const& r) { return l.db < r.db; }
+};
+
+static inline bool operator==(Tone const& lhs, Tone const& rhs) { return lhs == rhs.freq; }
+static inline bool operator!=(Tone const& lhs, Tone const& rhs) { return !(lhs == rhs); }
+static inline bool operator<=(Tone const& lhs, Tone const& rhs) { return lhs.freq < rhs.freq || lhs == rhs; }
+static inline bool operator>=(Tone const& lhs, Tone const& rhs) { return lhs.freq > rhs.freq || lhs == rhs; }
+static inline bool operator<(Tone const& lhs, Tone const& rhs) { return lhs.freq < rhs.freq && lhs != rhs; }
+static inline bool operator>(Tone const& lhs, Tone const& rhs) { return lhs.freq > rhs.freq && lhs != rhs; }
+
+static const unsigned FFT_P = 10;
+static const std::size_t FFT_N = 1 << FFT_P;
+
+/// Lock-free ring buffer. Discards oldest data on overflow (not strictly thread-safe).
+template class RingBuffer {
+public:
+ constexpr static size_t capacity = SIZE;
+ RingBuffer(): m_read(), m_write() {} ///< Initialize empty buffer
+ template void insert(InIt begin, InIt end) {
+ size_t r = m_read; // The read position
+ size_t w = m_write; // The write position
+ bool overflow = (static_cast(end - begin) >= SIZE - size());
+ while (begin != end) {
+ m_buf[w] = *begin++; // Copy sample
+ w = modulo(w + 1); // Update cursor
+ }
+ m_write = w;
+ if (overflow) m_read = modulo(w + 1); // Reset read pointer on overflow
+ }
+ /// Read data from current position if there is enough data to fill the range (otherwise return false). Does not move read pointer.
+ template bool read(OutIt begin, OutIt end) {
+ size_t r = m_read;
+ if (size() < static_cast(end - begin)) return false; // Not enough audio available
+ while (begin != end) *begin++ = m_buf[r++ % SIZE]; // Copy audio to output iterator
+ return true;
+ }
+ void pop(size_t n) { m_read = modulo(m_read + n); } ///< Move reading pointer forward.
+ size_t size() const { return modulo(m_write - m_read); }
+private:
+ static size_t modulo(size_t idx) { return idx % SIZE; } ///< Modulo operation with proper rounding (handles slightly "negative" idx as well)
+ float m_buf[SIZE];
+ volatile size_t m_read, m_write; ///< The indices of the next read/write operations. read == write implies that buffer is empty.
+};
+
+/// analyzer class
+ /** class to analyze input audio and transform it into useable data
+ */
+class Analyzer {
+public:
+ /// fast fourier transform vector
+ typedef std::vector > fft_t;
+ /// list of tones
+ typedef std::list tones_t;
+ /// constructor
+ Analyzer(double rate, std::string id, unsigned step = 200);
+ /** Add input data to buffer. This is thread-safe (against other functions). **/
+ template void input(InIt begin, InIt end) {
+ m_buf.insert(begin, end);
+ m_passthrough.insert(begin, end);
+ }
+ /** Call this to process all data input so far. **/
+ void process();
+ /** Get the raw FFT. **/
+ fft_t const& getFFT() const { return m_fft; }
+ /** Get the peak level in dB (negative value, 0.0 = clipping). **/
+ double getPeak() const { return 10.0 * log10(m_peak); }
+ /** Get a list of all tones detected. **/
+ tones_t const& getTones() const { return m_tones; }
+ /** Find a tone within the singing range; prefers strong tones around 200-400 Hz. **/
+ Tone const* findTone(double minfreq = 65.0, double maxfreq = 1000.0) const {
+ if (m_tones.empty()) { m_oldfreq = 0.0; return NULL; }
+ double db = std::max_element(m_tones.begin(), m_tones.end(), Tone::dbCompare)->db;
+ Tone const* best = NULL;
+ double bestscore = 0;
+ for (tones_t::const_iterator it = m_tones.begin(); it != m_tones.end(); ++it) {
+ if (it->db < db - 20.0 || it->freq < minfreq || it->age < Tone::MINAGE) continue;
+ if (it->freq > maxfreq) break;
+ double score = it->db - std::max(180.0, std::abs(it->freq - 300.0)) / 10.0;
+ if (m_oldfreq != 0.0 && std::fabs(it->freq/m_oldfreq - 1.0) < 0.05) score += 10.0;
+ if (best && bestscore > score) break;
+ best = &*it;
+ bestscore = score;
+ }
+ m_oldfreq = (best ? best->freq : 0.0);
+ return best;
+ }
+ /** Give data away for mic pass-through */
+ bool output(float* begin, float* end, double rate);
+ /** Returns the id (color name) of the mic */
+ std::string const& getId() const { return m_id; }
+
+private:
+ const unsigned m_step;
+ RingBuffer<4 * FFT_N> m_buf; // Twice the FFT size should give enough room for sliding window and for engine delays
+ RingBuffer<4096> m_passthrough;
+ double m_resampleFactor;
+ double m_resamplePos;
+ double m_rate;
+ std::string m_id;
+ std::vector m_window;
+ fft_t m_fft;
+ std::vector m_fftLastPhase;
+ double m_peak;
+ tones_t m_tones;
+ mutable double m_oldfreq;
+ bool calcFFT();
+ void calcTones();
+ void mergeWithOld(tones_t& tones) const;
+};
diff --git a/PitchTracker/performous/util.hh b/PitchTracker/performous/util.hh
new file mode 100644
index 00000000..f07753d4
--- /dev/null
+++ b/PitchTracker/performous/util.hh
@@ -0,0 +1,45 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+/** Limit val to range [min, max] **/
+template T clamp(T val, T min = 0, T max = 1) {
+ if (min > max) throw std::logic_error("min > max");
+ if (val < min) return min;
+ if (val > max) return max;
+ return val;
+}
+
+template struct MinMax {
+ Numeric min, max;
+ explicit MinMax(Numeric min = std::numeric_limits::min(), Numeric max = std::numeric_limits::max()): min(min), max(max) {}
+ bool matches(Numeric val) const { return val >= min && val <= max; }
+};
+
+/** A convenient way for getting NaNs **/
+static inline double getNaN() { return std::numeric_limits::quiet_NaN(); }
+
+/** A convenient way for getting infs **/
+static inline double getInf() { return std::numeric_limits::infinity(); }
+
+static inline bool isPow2(unsigned int val) {
+ if (val == 0) return false;
+ if ((val & (val-1)) == 0) return true; // From Wikipedia: Power_of_two
+ return false;
+}
+
+static inline unsigned int nextPow2(unsigned int val) {
+ unsigned int ret = 1;
+ while (ret < val) ret *= 2;
+ return ret;
+}
+
+static inline unsigned int prevPow2(unsigned int val) {
+ unsigned int ret = 1;
+ while ((ret*2) < val) ret *= 2;
+ return ret;
+}
+
diff --git a/PitchTracker/ptAKF.cpp b/PitchTracker/ptAKF.cpp
new file mode 100644
index 00000000..fd272a6f
--- /dev/null
+++ b/PitchTracker/ptAKF.cpp
@@ -0,0 +1,226 @@
+// This file is part of Vocaluxe.
+//
+// Vocaluxe 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 3 of the License, or
+// (at your option) any later version.
+//
+// Vocaluxe 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 Vocaluxe. If not, see .
+
+#include "ptAKF.h"
+#include
+
+static constexpr double BaseToneFrequency = 65.4064; // lowest (half-)tone to analyze (C2 = 65.4064 Hz)
+static constexpr double HalftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave)
+int PtAKF::_InitCount = 0;
+float* PtAKF::_SamplesPerPeriodPerTone = NULL;
+
+PtAKF::PtAKF(){
+ _InitCount++;
+ if(_InitCount == 1){
+ _SamplesPerPeriodPerTone = new float[_MaxHalfTone + 1];
+ //Init Array to avoid costly calculations
+ for (int toneIndex = 0; toneIndex <= _MaxHalfTone; toneIndex++)
+ {
+ double freq = BaseToneFrequency * pow(HalftoneBase, toneIndex);
+ _SamplesPerPeriodPerTone[toneIndex] = static_cast(44100.0 / freq); // samples in one period
+ }
+ }
+}
+
+PtAKF::~PtAKF(){
+ _InitCount--;
+ if(!_InitCount){
+ delete[] _SamplesPerPeriodPerTone;
+ _SamplesPerPeriodPerTone = NULL;
+ }
+}
+
+int PtAKF::GetNote(double* maxVolume, float* weights){
+ float AnaylsisBuf[_SampleCt];
+ size_t size = _AnalysisBuf.size();
+ if(size > _SampleCt)
+ _AnalysisBuf.pop(size - _SampleCt);
+ if(!_AnalysisBuf.read(AnaylsisBuf, AnaylsisBuf + _SampleCt))
+ return -1;
+ return _GetNote(AnaylsisBuf, maxVolume, weights);
+}
+
+int PtAKF::_GetNote(float* samples, double* maxVolume, float* weights){
+ float maxVolumeL = 0;
+ for(int i = 0; i < _SampleCt; i++){
+ float vol = abs(samples[i]);
+ if(vol > maxVolumeL)
+ maxVolumeL = vol;
+ }
+ maxVolumeL /= 32767.;
+ *maxVolume = maxVolumeL;
+
+ float maxWeight = -1;
+ float minWeight = 1;
+ int maxTone = -1;
+ for (int toneIndex = _MinHalfTone; toneIndex <= _MaxHalfTone; toneIndex++)
+ {
+ float curWeight = _AnalyzeToneFunc(samples, toneIndex);
+
+ if (curWeight > maxWeight)
+ {
+ maxWeight = curWeight;
+ maxTone = toneIndex;
+ }
+
+ if (curWeight < minWeight)
+ minWeight = curWeight;
+
+ weights[toneIndex - _MinHalfTone] = curWeight;
+ }
+
+ if(maxWeight - minWeight > 0.01){
+ return maxTone;
+ }else return -1;
+}
+
+float PtAKF::_AnalyzeToneFunc(float* samples, int toneIndex){
+ // Use method by Kobayashi and Shimamura (1995): Combine AKF and AMDF to a new f(z)=AKF(z)/(AMDF(z)+k) with k=1
+
+ float samplesPerPeriodD = _SamplesPerPeriodPerTone[toneIndex]; // samples in one period
+ int samplesPerPeriod = static_cast(samplesPerPeriodD);
+ float fHigh = samplesPerPeriodD - samplesPerPeriod;
+ float fLow = 1.0f - fHigh;
+
+ float accumDistAKF = 0; // accumulated distances
+ float accumDistAMDF = 0; // accumulated distances
+
+ // compare correlating samples
+ int sampleIndex = 0; // index of sample to analyze
+ // Start value= index of sample one period ahead
+ for (int correlatingSampleIndex = sampleIndex + samplesPerPeriod; correlatingSampleIndex + 1 < _SampleCt; correlatingSampleIndex++, sampleIndex++)
+ {
+ // calc distance to corresponding sample in next period
+ float xn = samples[sampleIndex];
+ float xnt = samples[correlatingSampleIndex] * fLow + samples[correlatingSampleIndex + 1] * fHigh;
+ accumDistAKF += xn * xnt;
+ accumDistAMDF += abs(xn - xnt);
+ }
+
+ accumDistAKF /= _SampleCt;
+ accumDistAMDF /= sampleIndex;
+
+ return accumDistAKF / (accumDistAMDF * 32767.f + 32767.f); // Need to scale AKF by MAX^2 and AMDF by MAX, so do some maths to divide only once
+}
+/*
+
+
+
+namespace PitchTrackerAKF{
+ static double *SamplesPerPeriodPerTone = NULL;
+ static double BaseToneFrequency = -1;
+ static int MinHalfTone = -1, MaxHalfTone = -1;
+ static const double HalftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave)
+
+ void Init(double baseToneFrequency, int minHalfTone, int maxHalfTone){
+ if(SamplesPerPeriodPerTone && abs(baseToneFrequency - BaseToneFrequency) < 1. && minHalfTone == MinHalfTone && maxHalfTone == MaxHalfTone)
+ return;
+ BaseToneFrequency = baseToneFrequency;
+ MinHalfTone = minHalfTone;
+ MaxHalfTone = maxHalfTone;
+ DeInit();
+ if(minHalfTone < 0 || maxHalfTone < minHalfTone)
+ return;
+ SamplesPerPeriodPerTone = (double*) malloc((MaxHalfTone + 1) * sizeof(double));
+ //Init Array to avoid costly calculations
+ for (int toneIndex = 0; toneIndex <= MaxHalfTone; toneIndex++)
+ {
+ double freq = baseToneFrequency * pow(HalftoneBase, toneIndex);
+ SamplesPerPeriodPerTone[toneIndex] = 44100.0 / freq; // samples in one period
+ }
+ }
+
+ void DeInit(){
+ if(SamplesPerPeriodPerTone){
+ free(SamplesPerPeriodPerTone);
+ SamplesPerPeriodPerTone=NULL;
+ }
+ }
+
+ template
+ static T _AnalyzeToneFunc(T *samples, int sampleCt, int toneIndex, bool scale){
+ // Use method by Kobayashi and Shimamura (1995): Combine AKF and AMDF to a new f(z)=AKF(z)/(AMDF(z)+k) with k=1
+ double samplesPerPeriodD = SamplesPerPeriodPerTone[toneIndex]; // samples in one period
+ int samplesPerPeriod = static_cast(samplesPerPeriodD);
+ T fHigh = static_cast(samplesPerPeriodD - samplesPerPeriod);
+ T fLow = static_cast(1.0 - fHigh);
+
+ T accumDistAKF = 0; // accumulated distances
+ T accumDistAMDF = 0; // accumulated distances
+
+ // compare correlating samples
+ int sampleIndex = 0; // index of sample to analyze
+ // Start value= index of sample one period ahead
+ for (int correlatingSampleIndex = sampleIndex + samplesPerPeriod; correlatingSampleIndex + 1 < sampleCt; correlatingSampleIndex++, sampleIndex++)
+ {
+ // calc distance to corresponding sample in next period
+ T xn = samples[sampleIndex];
+ T xnt = samples[correlatingSampleIndex] * fLow + samples[correlatingSampleIndex + 1] * fHigh;
+ accumDistAKF += xn * xnt;
+ accumDistAMDF += abs(xn - xnt);
+ }
+
+ accumDistAKF /= sampleCt;
+ accumDistAMDF /= sampleIndex;
+
+ if(scale)
+ return accumDistAKF / (accumDistAMDF * 32767.f + 32767.f); // Need to scale AKF by MAX^2 and AMDF by MAX, so do some maths to divide only once
+ else
+ return accumDistAKF / (accumDistAMDF + 1.f);
+ }
+
+ template
+ int GetTone(T *samples, int sampleCt, double* maxVolume, float *weights, bool scale){
+ if(!SamplesPerPeriodPerTone)
+ return -1;
+ T maxVolumeL = 0;
+ for(int i = 0; i < sampleCt; i++){
+ T vol = abs(samples[i]);
+ if(vol > maxVolumeL)
+ maxVolumeL = vol;
+ }
+ if(scale)
+ maxVolumeL /= 32767.;
+ *maxVolume = maxVolumeL;
+
+ T maxWeight = -1;
+ T minWeight = 1;
+ int maxTone = -1;
+ for (int toneIndex = MinHalfTone; toneIndex <= MaxHalfTone; toneIndex++)
+ {
+ T curWeight = _AnalyzeToneFunc(samples, sampleCt, toneIndex, scale);
+
+ if (curWeight > maxWeight)
+ {
+ maxWeight = curWeight;
+ maxTone = toneIndex;
+ }
+
+ if (curWeight < minWeight)
+ minWeight = curWeight;
+
+ weights[toneIndex - MinHalfTone] = static_cast(curWeight);
+ }
+
+ if(maxWeight - minWeight > 0.01){
+ return maxTone;
+ }else return -1;
+ }
+
+ template int GetTone(float *samples, int sampleCt, double* maxVolume, float *weights, bool scale);
+ template int GetTone(double *samples, int sampleCt, double* maxVolume, float *weights, bool scale);
+
+}
+*/
\ No newline at end of file
diff --git a/PitchTracker/ptAKF.h b/PitchTracker/ptAKF.h
new file mode 100644
index 00000000..240e7aa7
--- /dev/null
+++ b/PitchTracker/ptAKF.h
@@ -0,0 +1,27 @@
+#pragma once
+#include "performous/pitch.hh"
+
+// A pitch detection that is based on the AKF and AMDF (initially from original Vocaluxe/USDx)
+class PtAKF{
+public:
+ PtAKF();
+ ~PtAKF();
+
+ void input(short* begin, short* end){
+ _AnalysisBuf.insert(begin, end);
+ }
+
+ int GetNote(double* maxVolume, float* weights);
+ static int GetNumHalfTones(){ return _MaxHalfTone - _MinHalfTone + 1;}
+private:
+ static int _InitCount;
+ static float* _SamplesPerPeriodPerTone;
+ static constexpr int _MinHalfTone = 0; //C2
+ static constexpr int _MaxHalfTone = 47; //B5
+
+ constexpr static size_t _SampleCt = 4096;
+ RingBuffer<_SampleCt * 2> _AnalysisBuf;
+
+ static int _GetNote(float* samples, double* maxVolume, float* weights);
+ static float _AnalyzeToneFunc(float* samples, int toneIndex);
+};
\ No newline at end of file
diff --git a/Vocaluxe.sln b/Vocaluxe.sln
index 5d225110..0298c529 100644
--- a/Vocaluxe.sln
+++ b/Vocaluxe.sln
@@ -9,6 +9,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocalu
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3} = {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}
{D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} = {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC}
{5A4053F1-5AD5-441F-B254-D97A088127B6} = {5A4053F1-5AD5-441F-B254-D97A088127B6}
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A} = {54A48AF7-515C-4EDD-B395-2BFFA096050A}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VocaluxeLib", "VocaluxeLib\VocaluxeLib.csproj", "{D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC}"
@@ -25,6 +26,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerLib", "ClientServerLi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebserverInitalConfig", "WebserverInitalConfig\WebserverInitalConfig.csproj", "{55F89808-4E79-4FFE-BC13-48258913F5C9}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PitchTracker", "PitchTracker\PitchTracker.vcxproj", "{54A48AF7-515C-4EDD-B395-2BFFA096050A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
DebugLinux|x64 = DebugLinux|x64
@@ -108,7 +111,9 @@ Global
{5A4053F1-5AD5-441F-B254-D97A088127B6}.DebugWin|x86.ActiveCfg = DebugWin|x86
{5A4053F1-5AD5-441F-B254-D97A088127B6}.DebugWin|x86.Build.0 = DebugWin|x86
{5A4053F1-5AD5-441F-B254-D97A088127B6}.InstallerWin|x64.ActiveCfg = ReleaseWin|x64
+ {5A4053F1-5AD5-441F-B254-D97A088127B6}.InstallerWin|x64.Build.0 = ReleaseWin|x64
{5A4053F1-5AD5-441F-B254-D97A088127B6}.InstallerWin|x86.ActiveCfg = ReleaseWin|x86
+ {5A4053F1-5AD5-441F-B254-D97A088127B6}.InstallerWin|x86.Build.0 = ReleaseWin|x86
{5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|x64
{5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseLinux|x64.Build.0 = ReleaseLinux|x64
{5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseLinux|x86.ActiveCfg = ReleaseLinux|x86
@@ -126,7 +131,9 @@ Global
{6F3E1874-F28A-40E9-AFBD-31934D593678}.DebugWin|x86.ActiveCfg = DebugWin|x86
{6F3E1874-F28A-40E9-AFBD-31934D593678}.DebugWin|x86.Build.0 = DebugWin|x86
{6F3E1874-F28A-40E9-AFBD-31934D593678}.InstallerWin|x64.ActiveCfg = ReleaseWin|x64
+ {6F3E1874-F28A-40E9-AFBD-31934D593678}.InstallerWin|x64.Build.0 = ReleaseWin|x64
{6F3E1874-F28A-40E9-AFBD-31934D593678}.InstallerWin|x86.ActiveCfg = ReleaseWin|x86
+ {6F3E1874-F28A-40E9-AFBD-31934D593678}.InstallerWin|x86.Build.0 = ReleaseWin|x86
{6F3E1874-F28A-40E9-AFBD-31934D593678}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|x64
{6F3E1874-F28A-40E9-AFBD-31934D593678}.ReleaseLinux|x64.Build.0 = ReleaseLinux|x64
{6F3E1874-F28A-40E9-AFBD-31934D593678}.ReleaseLinux|x86.ActiveCfg = ReleaseLinux|x86
@@ -142,7 +149,9 @@ Global
{ED007796-367F-4142-AA55-5450C7645C2C}.DebugWin|x86.ActiveCfg = DebugWin|Win32
{ED007796-367F-4142-AA55-5450C7645C2C}.DebugWin|x86.Build.0 = DebugWin|Win32
{ED007796-367F-4142-AA55-5450C7645C2C}.InstallerWin|x64.ActiveCfg = ReleaseWin|x64
+ {ED007796-367F-4142-AA55-5450C7645C2C}.InstallerWin|x64.Build.0 = ReleaseWin|x64
{ED007796-367F-4142-AA55-5450C7645C2C}.InstallerWin|x86.ActiveCfg = ReleaseWin|Win32
+ {ED007796-367F-4142-AA55-5450C7645C2C}.InstallerWin|x86.Build.0 = ReleaseWin|Win32
{ED007796-367F-4142-AA55-5450C7645C2C}.ReleaseLinux|x64.ActiveCfg = ReleaseWin|x64
{ED007796-367F-4142-AA55-5450C7645C2C}.ReleaseLinux|x86.ActiveCfg = ReleaseWin|x64
{ED007796-367F-4142-AA55-5450C7645C2C}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64
@@ -152,18 +161,23 @@ Global
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugLinux|x64.ActiveCfg = DebugLinux|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugLinux|x64.Build.0 = DebugLinux|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugLinux|x86.ActiveCfg = DebugLinux|Any CPU
+ {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugLinux|x86.Build.0 = DebugLinux|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugWin|x64.ActiveCfg = DebugWin|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugWin|x64.Build.0 = DebugWin|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugWin|x86.ActiveCfg = DebugWin|Any CPU
+ {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugWin|x86.Build.0 = DebugWin|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.InstallerWin|x64.ActiveCfg = ReleaseWin|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.InstallerWin|x64.Build.0 = ReleaseWin|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.InstallerWin|x86.ActiveCfg = ReleaseLinux|Any CPU
+ {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.InstallerWin|x86.Build.0 = ReleaseLinux|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseLinux|x64.Build.0 = ReleaseLinux|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseLinux|x86.ActiveCfg = ReleaseLinux|Any CPU
+ {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseLinux|x86.Build.0 = ReleaseLinux|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseWin|x64.ActiveCfg = ReleaseWin|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU
+ {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugLinux|x64.ActiveCfg = Debug|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugLinux|x86.ActiveCfg = Debug|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugWin|x64.ActiveCfg = Debug|Any CPU
@@ -173,12 +187,33 @@ Global
{55F89808-4E79-4FFE-BC13-48258913F5C9}.InstallerWin|x64.ActiveCfg = Release|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.InstallerWin|x64.Build.0 = Release|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.InstallerWin|x86.ActiveCfg = Release|Any CPU
+ {55F89808-4E79-4FFE-BC13-48258913F5C9}.InstallerWin|x86.Build.0 = Release|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseLinux|x64.ActiveCfg = Release|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseLinux|x86.ActiveCfg = Release|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x64.ActiveCfg = Release|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x64.Build.0 = Release|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x86.ActiveCfg = Release|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x86.Build.0 = Release|Any CPU
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugLinux|x64.ActiveCfg = Debug|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugLinux|x64.Build.0 = Debug|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugLinux|x86.ActiveCfg = Debug|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugLinux|x86.Build.0 = Debug|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugWin|x64.ActiveCfg = Debug|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugWin|x64.Build.0 = Debug|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugWin|x86.ActiveCfg = Debug|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugWin|x86.Build.0 = Debug|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.InstallerWin|x64.ActiveCfg = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.InstallerWin|x64.Build.0 = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.InstallerWin|x86.ActiveCfg = Release|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.InstallerWin|x86.Build.0 = Release|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseLinux|x64.ActiveCfg = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseLinux|x64.Build.0 = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseLinux|x86.ActiveCfg = Release|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseLinux|x86.Build.0 = Release|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseWin|x64.ActiveCfg = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseWin|x64.Build.0 = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseWin|x86.ActiveCfg = Release|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseWin|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Vocaluxe/Base/CBackgroundMusic.cs b/Vocaluxe/Base/CBackgroundMusic.cs
index 9afc32dd..c06c0b2c 100644
--- a/Vocaluxe/Base/CBackgroundMusic.cs
+++ b/Vocaluxe/Base/CBackgroundMusic.cs
@@ -17,8 +17,8 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
-using System.Linq;
using VocaluxeLib;
using VocaluxeLib.Songs;
using VocaluxeLib.Draw;
@@ -27,25 +27,28 @@ namespace Vocaluxe.Base
{
static class CBackgroundMusic
{
- private static int _CurrentMusicStream = -1;
- private static int _PreviousMusicIndex;
- private static CPlaylistElement _CurrentPlaylistElement = new CPlaylistElement();
+ private static bool _Initialized;
- private static readonly List _AllFileNames = new List();
- private static readonly List _NotPlayedFileNames = new List();
- private static readonly List _BGMusicFileNames = new List();
- private static readonly List _PreviousFileNames = new List();
+ private static bool _OwnSongsAvailable;
+ private static EBackgroundMusicSource _MusicSource;
+ private static float _Volume;
+ private static bool _VideoEnabled;
+
+ private static CPlaylistElement _CurrentPlaylistElement; //Currently played music
+ private static int _CurrentMusicStream = -1; //Current active music stream
+ private static int _PreviousMusicIndex; //Index of _CurrentPlaylistElement in _PreviousFiles (kept for performance)
+
+ private static readonly List _BGMusicFiles = new List(); //Background music files
+ private static readonly List _NotPlayedFiles = new List(); //Not played files
+ private static readonly List _PreviousFiles = new List(); //Played files
private static int _Video = -1;
private static CTexture _CurrentVideoTexture;
private static CFading _VideoFading;
- private static bool _VideoEnabled;
private static bool _OwnMusicAdded;
private static bool _BackgroundMusicAdded;
private static bool _Disabled;
- private static bool _CanSing;
- private static bool _RepeatSong;
public static bool VideoEnabled
{
@@ -54,16 +57,19 @@ namespace Vocaluxe.Base
{
if (_VideoEnabled == value)
return;
- ToggleVideo();
_VideoEnabled = value;
+ if (_VideoEnabled)
+ _LoadVideo();
+ else if (_Video != -1)
+ {
+ CVideo.Close(_Video);
+ CDraw.RemoveTexture(ref _CurrentVideoTexture);
+ _Video = -1;
+ }
}
}
- public static bool CanSing
- {
- get { return _CanSing; }
- set { _CanSing = value; }
- }
+ public static bool CanSing { get; private set; }
public static bool Disabled
{
@@ -78,20 +84,16 @@ namespace Vocaluxe.Base
}
}
- public static bool RepeatSong
- {
- get { return _RepeatSong; }
- set { _RepeatSong = value; }
- }
+ public static bool RepeatSong { get; set; }
public static int SongID
{
- get { return _CurrentPlaylistElement.SongID; }
+ get { return _CurrentPlaylistElement == null ? -1 : _CurrentPlaylistElement.SongID; }
}
public static bool SongHasVideo
{
- get { return File.Exists(_CurrentPlaylistElement.VideoFilePath); }
+ get { return _CurrentPlaylistElement != null && File.Exists(_CurrentPlaylistElement.VideoFilePath); }
}
public static bool IsPlaying { get; private set; }
@@ -100,6 +102,8 @@ namespace Vocaluxe.Base
{
get
{
+ if (_CurrentPlaylistElement == null)
+ return "";
if (_CurrentPlaylistElement.Artist != "" && _CurrentPlaylistElement.Title != "")
return _CurrentPlaylistElement.Artist + " - " + _CurrentPlaylistElement.Title;
return Path.GetFileNameWithoutExtension(_CurrentPlaylistElement.MusicFilePath);
@@ -108,50 +112,63 @@ namespace Vocaluxe.Base
public static CTexture Cover
{
- get { return _CurrentPlaylistElement.Cover; }
+ get { return _CurrentPlaylistElement == null ? CCover.NoCover : _CurrentPlaylistElement.Cover; }
}
+ //Use this to set whether own songs are available for access
+ public static bool OwnSongsAvailable
+ {
+ get { return _OwnSongsAvailable; }
+ set
+ {
+ _OwnSongsAvailable = value;
+ if (_OwnSongsAvailable && _MusicSource != EBackgroundMusicSource.TR_CONFIG_NO_OWN_MUSIC)
+ _AddOwnMusic();
+ }
+ }
+
+ ///
+ /// Initializes the background music with values from config
+ /// Has to be called before any other method is used
+ ///
public static void Init()
{
- var templist = new List();
+ if (_Initialized)
+ return;
- foreach (string ending in CSettings.MusicFileTypes)
- templist.AddRange(CHelper.ListFiles(CSettings.FolderBackgroundMusic, ending, true, true));
+ List soundFiles = CHelper.ListSoundFiles(CSettings.FolderBackgroundMusic, true, true);
- foreach (string path in templist)
- _BGMusicFileNames.Add(new CPlaylistElement(path));
-
- if (CConfig.BackgroundMusicSource != EBackgroundMusicSource.TR_CONFIG_ONLY_OWN_MUSIC)
- AddBackgroundMusic();
-
- _VideoEnabled = (CConfig.VideoBackgrounds == EOffOn.TR_CONFIG_ON && CConfig.VideosToBackground == EOffOn.TR_CONFIG_ON);
+ foreach (string path in soundFiles)
+ _BGMusicFiles.Add(new CPlaylistElement(path));
+ //Set a default to have a consistent starting point, use SetMusicSource afterwards
+ _MusicSource = EBackgroundMusicSource.TR_CONFIG_NO_OWN_MUSIC;
+ _AddBackgroundMusic();
+ _PreviousMusicIndex = -1;
IsPlaying = false;
+ _Volume = CConfig.BackgroundMusicVolume;
+ _VideoEnabled = (CConfig.VideoBackgrounds == EOffOn.TR_CONFIG_ON && CConfig.VideosToBackground == EOffOn.TR_CONFIG_ON);
+ SetMusicSource(CConfig.BackgroundMusicSource);
+ _Initialized = true;
}
public static void Play()
{
- if (IsPlaying)
+ if (IsPlaying || CConfig.BackgroundMusic == EOffOn.TR_CONFIG_OFF)
return;
- if (CConfig.BackgroundMusic == EOffOn.TR_CONFIG_ON)
+ if (_CurrentMusicStream != -1)
{
- if (_AllFileNames.Count > 0)
- {
- if (_CurrentMusicStream != -1)
- {
- CSound.Fade(_CurrentMusicStream, 100f, CSettings.BackgroundMusicFadeTime);
- CSound.Play(_CurrentMusicStream);
- if (_VideoEnabled && _Video != -1)
- CVideo.Resume(_Video);
- IsPlaying = true;
- }
- else
- Next();
-
- _CanSing = !_IsBackgroundFile(_CurrentPlaylistElement);
- }
+ //Resume
+ CSound.SetStreamVolume(_CurrentMusicStream, 0f);
+ CSound.Fade(_CurrentMusicStream, _Volume, CSettings.BackgroundMusicFadeTime);
+ CSound.Play(_CurrentMusicStream);
+ if (_VideoEnabled && _Video != -1)
+ CVideo.Resume(_Video);
+ IsPlaying = true;
}
+ else
+ Next();
}
public static void Stop()
@@ -159,7 +176,7 @@ namespace Vocaluxe.Base
if (!IsPlaying)
return;
- if (_VideoEnabled && _Video != -1)
+ if (_Video != -1)
{
CVideo.Close(_Video);
CDraw.RemoveTexture(ref _CurrentVideoTexture);
@@ -168,7 +185,7 @@ namespace Vocaluxe.Base
CSound.FadeAndClose(_CurrentMusicStream, 0f, CSettings.BackgroundMusicFadeTime);
_CurrentMusicStream = -1;
- _CurrentPlaylistElement = new CPlaylistElement();
+ _CurrentPlaylistElement = null;
IsPlaying = false;
}
@@ -177,7 +194,7 @@ namespace Vocaluxe.Base
if (!IsPlaying)
return;
- if (_VideoEnabled && _Video != -1)
+ if (_Video != -1)
{
CVideo.Pause(_Video);
CVideo.Skip(_Video, CSound.GetPosition(_CurrentMusicStream) + CSettings.BackgroundMusicFadeTime, _CurrentPlaylistElement.VideoGap);
@@ -186,277 +203,204 @@ namespace Vocaluxe.Base
IsPlaying = false;
}
- public static void Update()
- {
- if (_AllFileNames.Count > 0 && _CurrentMusicStream != -1)
- {
- float timeToPlay;
- if (Math.Abs(_CurrentPlaylistElement.Finish) < 0.001) //No End-Tag defined
- timeToPlay = CSound.GetLength(_CurrentMusicStream) - CSound.GetPosition(_CurrentMusicStream);
- else //End-Tag found
- timeToPlay = _CurrentPlaylistElement.Finish - CSound.GetPosition(_CurrentMusicStream);
-
- bool finished = CSound.IsFinished(_CurrentMusicStream);
- if (IsPlaying && ((timeToPlay <= CSettings.BackgroundMusicFadeTime && timeToPlay > 0) || finished))
- {
- if (_RepeatSong)
- {
- //Seek to #Start-Tag, if found
- if (_CurrentPlaylistElement.Start > 0.001 && CConfig.BackgroundMusicUseStart == EOffOn.TR_CONFIG_ON)
- CSound.SetPosition(_CurrentMusicStream, _CurrentPlaylistElement.Start);
- else
- CSound.SetPosition(_CurrentMusicStream, 0);
- if (_VideoEnabled && _Video != -1)
- {
- if (_CurrentPlaylistElement.Start > 0.001 && CConfig.BackgroundMusicUseStart == EOffOn.TR_CONFIG_ON)
- CVideo.Skip(_Video, _CurrentPlaylistElement.Start, _CurrentPlaylistElement.VideoGap);
- else
- CVideo.Skip(_Video, 0f, _CurrentPlaylistElement.VideoGap);
- }
- }
- else
- Next();
- }
- }
- }
-
public static void Next()
{
- if (_AllFileNames.Count > 0)
+ Stop(); //stop last song if any
+ if (_PreviousMusicIndex < _PreviousFiles.Count - 2)
{
- if (_PreviousMusicIndex == _PreviousFileNames.Count - 1 || _PreviousFileNames.Count == 0)
- {
- //We are not currently in the previous list
- Stop();
- if (_NotPlayedFileNames.Count == 0)
- _NotPlayedFileNames.AddRange(_AllFileNames);
-
- _CurrentPlaylistElement = _NotPlayedFileNames[CGame.Rand.Next(_NotPlayedFileNames.Count)];
- _NotPlayedFileNames.Remove(_CurrentPlaylistElement);
-
- _PreviousFileNames.Add(_CurrentPlaylistElement);
- _PreviousMusicIndex = _PreviousFileNames.Count - 1;
- }
- else if (_PreviousFileNames.Count > 0)
- {
- //We are in the previous list
- Stop();
- _PreviousMusicIndex++;
-
- _CurrentPlaylistElement = _PreviousFileNames[_PreviousMusicIndex];
- }
- _CurrentMusicStream = CSound.Load(_CurrentPlaylistElement.MusicFilePath);
- CSound.SetStreamVolumeMax(_CurrentMusicStream, CConfig.BackgroundMusicVolume);
-
- //Seek to #Start-Tag, if found
- if (_CurrentPlaylistElement.Start > 0.001 && CConfig.BackgroundMusicUseStart == EOffOn.TR_CONFIG_ON)
- CSound.SetPosition(_CurrentMusicStream, _CurrentPlaylistElement.Start);
-
- if (_VideoEnabled)
- _LoadVideo();
- CSound.SetStreamVolume(_CurrentMusicStream, 0f);
- Play();
+ //We are in the previous list and next element exists
+ _PreviousMusicIndex++;
+ _CurrentPlaylistElement = _PreviousFiles[_PreviousMusicIndex];
}
else
- Stop();
+ {
+ //We are not in the previous list (anymore)
+ if (_NotPlayedFiles.Count == 0)
+ {
+ if (_PreviousFiles.Count == 0)
+ return; //No songs to play
+ _NotPlayedFiles.AddRange(_PreviousFiles);
+ }
+
+ _CurrentPlaylistElement = _NotPlayedFiles[CGame.Rand.Next(_NotPlayedFiles.Count)];
+ _NotPlayedFiles.Remove(_CurrentPlaylistElement);
+
+ _PreviousFiles.Add(_CurrentPlaylistElement);
+ _PreviousMusicIndex = _PreviousFiles.Count - 1;
+ }
+ _StartSong();
+ CanSing = !_IsBackgroundFile(_CurrentPlaylistElement);
}
public static void Previous()
{
- if (_PreviousFileNames.Count > 0 && _PreviousMusicIndex >= 0)
+ if (_PreviousMusicIndex < 0)
+ return;
+ Debug.Assert(_CurrentMusicStream != -1 && _CurrentPlaylistElement != null);
+ if (CSound.GetPosition(_CurrentMusicStream) <= 1.5f && _PreviousMusicIndex > 0)
{
- if (CSound.GetPosition(_CurrentMusicStream) >= 1.5f)
- {
- //Seek to #Start-Tag, if found
- if (_CurrentPlaylistElement.Start > 0.001 && CConfig.BackgroundMusicUseStart == EOffOn.TR_CONFIG_ON)
- CSound.SetPosition(_CurrentMusicStream, _CurrentPlaylistElement.Start);
- else
- CSound.SetPosition(_CurrentMusicStream, 0);
- if (_VideoEnabled && _Video != -1)
- {
- if (_CurrentPlaylistElement.Start > 0.001 && CConfig.BackgroundMusicUseStart == EOffOn.TR_CONFIG_ON)
- CVideo.Skip(_Video, _CurrentPlaylistElement.Start, _CurrentPlaylistElement.VideoGap);
- else
- CVideo.Skip(_Video, 0f, _CurrentPlaylistElement.VideoGap);
- }
- }
- else
- {
- Stop();
- _PreviousMusicIndex--;
- if (_PreviousMusicIndex < 0)
- _PreviousMusicIndex = 0; //No previous songs left, so play the first
+ Stop(); //stop last song
+ _PreviousMusicIndex--;
- _CurrentPlaylistElement = _PreviousFileNames[_PreviousMusicIndex];
-
- _CurrentMusicStream = CSound.Load(_CurrentPlaylistElement.MusicFilePath);
- CSound.SetStreamVolumeMax(_CurrentMusicStream, CConfig.BackgroundMusicVolume);
- if (_VideoEnabled)
- _LoadVideo();
- CSound.SetStreamVolume(_CurrentMusicStream, 0f);
- Play();
- }
+ _CurrentPlaylistElement = _PreviousFiles[_PreviousMusicIndex];
+ CanSing = !_IsBackgroundFile(_CurrentPlaylistElement);
}
- else if (_CurrentMusicStream != -1)
+ _StartSong();
+ }
+
+ public static void Update()
+ {
+ if (!IsPlaying)
+ return;
+ Debug.Assert(_CurrentMusicStream != -1 && _CurrentPlaylistElement != null);
+
+ float timeToPlay;
+ if (Math.Abs(_CurrentPlaylistElement.Finish) < 0.001) //No End-Tag defined
+ timeToPlay = CSound.GetLength(_CurrentMusicStream) - CSound.GetPosition(_CurrentMusicStream);
+ else //End-Tag found
+ timeToPlay = _CurrentPlaylistElement.Finish - CSound.GetPosition(_CurrentMusicStream);
+
+ bool finished = CSound.IsFinished(_CurrentMusicStream);
+ if (timeToPlay <= CSettings.BackgroundMusicFadeTime || finished)
{
- //Seek to #Start-Tag, if found
- if (_CurrentPlaylistElement.Start > 0.001 && CConfig.BackgroundMusicUseStart == EOffOn.TR_CONFIG_ON)
- CSound.SetPosition(_CurrentMusicStream, _CurrentPlaylistElement.Start);
+ if (RepeatSong)
+ _StartSong();
else
- CSound.SetPosition(_CurrentMusicStream, 0);
- if (_VideoEnabled && _Video != -1)
+ Next();
+ }
+ }
+
+ public static CTexture GetVideoTexture()
+ {
+ if (_Video == -1)
+ return null;
+ float vtime;
+ if (CVideo.GetFrame(_Video, ref _CurrentVideoTexture, CSound.GetPosition(_CurrentMusicStream), out vtime))
+ {
+ if (_VideoFading != null)
+ {
+ bool finished;
+ _CurrentVideoTexture.Color.A = _VideoFading.GetValue(out finished);
+ if (finished)
+ _VideoFading = null;
+ }
+ return _CurrentVideoTexture;
+ }
+ return null;
+ }
+
+ public static void SetMusicSource(EBackgroundMusicSource source)
+ {
+ if (_MusicSource == source)
+ return;
+ _MusicSource = source;
+ switch (_MusicSource)
+ {
+ case EBackgroundMusicSource.TR_CONFIG_NO_OWN_MUSIC:
+ _AddBackgroundMusic();
+ _RemoveOwnMusic();
+ break;
+
+ case EBackgroundMusicSource.TR_CONFIG_ONLY_OWN_MUSIC:
+ _AddOwnMusic();
+ _RemoveBackgroundMusic();
+ break;
+ case EBackgroundMusicSource.TR_CONFIG_OWN_MUSIC:
+ _AddBackgroundMusic();
+ _AddOwnMusic();
+ break;
+ }
+ }
+
+ public static void SetVolume(float volume)
+ {
+ _Volume = volume;
+ if (_CurrentMusicStream >= 0)
+ CSound.SetStreamVolume(_CurrentMusicStream, _Volume);
+ }
+
+ ///
+ /// (Re-)Starts the _CurrentPlaylistElement
+ ///
+ private static void _StartSong()
+ {
+ Debug.Assert(_CurrentPlaylistElement != null);
+ //If we have an active stream, reuse it
+ if (_CurrentMusicStream < 0)
+ {
+ //otherwhise load
+ _CurrentMusicStream = CSound.Load(_CurrentPlaylistElement.MusicFilePath);
+ if (_CurrentMusicStream < 0)
+ return;
+ CSound.SetStreamVolume(_CurrentMusicStream, 0f);
+ CSound.Fade(_CurrentMusicStream, _Volume, CSettings.BackgroundMusicFadeTime);
+ }
+ //Seek to #Start-Tag, if found
+ if (_CurrentPlaylistElement.Start > 0.001 && CConfig.BackgroundMusicUseStart == EOffOn.TR_CONFIG_ON)
+ CSound.SetPosition(_CurrentMusicStream, _CurrentPlaylistElement.Start);
+
+ if (_VideoEnabled)
+ {
+ if (_Video != -1)
{
if (_CurrentPlaylistElement.Start > 0.001 && CConfig.BackgroundMusicUseStart == EOffOn.TR_CONFIG_ON)
- CVideo.Skip(_Video, _CurrentPlaylistElement.Start, _CurrentPlaylistElement.VideoGap);
+ CVideo.Skip(_Video, 0f, _CurrentPlaylistElement.VideoGap + _CurrentPlaylistElement.Start);
else
CVideo.Skip(_Video, 0f, _CurrentPlaylistElement.VideoGap);
}
+ else
+ _LoadVideo();
}
}
- public static void ApplyVolume()
+ private static void _AddOwnMusic()
{
- CSound.SetStreamVolumeMax(_CurrentMusicStream, CConfig.BackgroundMusicVolume);
- }
-
- public static void AddOwnMusic()
- {
- if (!_OwnMusicAdded)
- {
- foreach (CSong song in CSongs.AllSongs)
- {
- _AllFileNames.Add(new CPlaylistElement(song));
- _NotPlayedFileNames.Add(new CPlaylistElement(song));
- }
- }
+ if (_OwnMusicAdded || !_OwnSongsAvailable)
+ return;
+ foreach (CSong song in CSongs.AllSongs)
+ _NotPlayedFiles.Add(new CPlaylistElement(song));
_OwnMusicAdded = true;
}
- public static void RemoveOwnMusic()
+ private static void _RemoveOwnMusic()
{
- _AllFileNames.Clear();
- _NotPlayedFileNames.Clear();
+ if (!_OwnMusicAdded)
+ return;
+ _NotPlayedFiles.RemoveAll(el => el.SongID >= 0);
+ _PreviousFiles.RemoveAll(el => el.SongID >= 0);
+ _PreviousMusicIndex = _PreviousFiles.IndexOf(_CurrentPlaylistElement);
- if (_BackgroundMusicAdded)
- {
- _AllFileNames.AddRange(_BGMusicFileNames);
- _NotPlayedFileNames.AddRange(_BGMusicFileNames);
- }
-
- if (IsPlaying && !_IsBackgroundFile(_CurrentPlaylistElement) || _AllFileNames.Count == 0)
+ if (IsPlaying && !_IsBackgroundFile(_CurrentPlaylistElement))
Next();
_OwnMusicAdded = false;
}
- public static void AddBackgroundMusic()
- {
- if (!_BackgroundMusicAdded)
- {
- _AllFileNames.AddRange(_BGMusicFileNames);
- _NotPlayedFileNames.AddRange(_BGMusicFileNames);
- _BackgroundMusicAdded = true;
- }
- }
-
- public static void RemoveBackgroundMusic()
+ private static void _AddBackgroundMusic()
{
if (_BackgroundMusicAdded)
- {
- _AllFileNames.Clear();
- _OwnMusicAdded = false;
- AddOwnMusic();
- _BackgroundMusicAdded = false;
-
- if (IsPlaying && _IsBackgroundFile(_CurrentPlaylistElement) || _AllFileNames.Count == 0)
- Next();
- }
+ return;
+ _NotPlayedFiles.AddRange(_BGMusicFiles);
+ _BackgroundMusicAdded = true;
}
- public static void CheckAndApplyConfig(EOffOn newOnOff, EBackgroundMusicSource newSource, float newVolume)
+ private static void _RemoveBackgroundMusic()
{
- if (CConfig.BackgroundMusicSource != newSource || (newOnOff == EOffOn.TR_CONFIG_ON && !_OwnMusicAdded && !_BackgroundMusicAdded))
- {
- CConfig.BackgroundMusicSource = newSource;
+ if (!_BackgroundMusicAdded)
+ return;
+ _NotPlayedFiles.RemoveAll(el => el.SongID < 0);
+ _PreviousFiles.RemoveAll(el => el.SongID < 0);
+ _PreviousMusicIndex = _PreviousFiles.IndexOf(_CurrentPlaylistElement);
- switch (newSource)
- {
- case EBackgroundMusicSource.TR_CONFIG_NO_OWN_MUSIC:
- if (!_BackgroundMusicAdded)
- AddBackgroundMusic();
+ if (IsPlaying && _IsBackgroundFile(_CurrentPlaylistElement))
+ Next();
- RemoveOwnMusic();
- break;
-
- case EBackgroundMusicSource.TR_CONFIG_ONLY_OWN_MUSIC:
- if (!_OwnMusicAdded)
- AddOwnMusic();
-
- RemoveBackgroundMusic();
- break;
- case EBackgroundMusicSource.TR_CONFIG_OWN_MUSIC:
- if (!_BackgroundMusicAdded)
- AddBackgroundMusic();
-
- if (!_OwnMusicAdded)
- AddOwnMusic();
- break;
- }
- }
-
- if (CConfig.BackgroundMusic != newOnOff)
- {
- CConfig.BackgroundMusic = newOnOff;
- if (newOnOff == EOffOn.TR_CONFIG_ON)
- Play();
- else
- Pause();
- }
-
- if (Math.Abs(CConfig.BackgroundMusicVolume - newVolume) > 0.01)
- {
- CConfig.BackgroundMusicVolume = (int)newVolume;
- ApplyVolume();
- }
-
- CConfig.SaveConfig();
- }
-
- public static void ToggleVideo()
- {
- if (_Video != -1)
- {
- CVideo.Close(_Video);
- CDraw.RemoveTexture(ref _CurrentVideoTexture);
- _Video = -1;
- }
- else
- _LoadVideo();
- }
-
- public static CTexture GetVideoTexture()
- {
- if (_Video != -1)
- {
- float vtime;
- if (CVideo.GetFrame(_Video, ref _CurrentVideoTexture, CSound.GetPosition(_CurrentMusicStream), out vtime))
- {
- if (_VideoFading != null)
- {
- bool finished;
- _CurrentVideoTexture.Color.A = _VideoFading.GetValue(out finished);
- if (finished)
- _VideoFading = null;
- }
- return _CurrentVideoTexture;
- }
- }
- return null;
+ _BackgroundMusicAdded = false;
}
private static bool _IsBackgroundFile(CPlaylistElement element)
{
- return _BGMusicFileNames.Any(elements => elements.MusicFilePath == element.MusicFilePath);
+ return _BGMusicFiles.Contains(element);
}
private static void _LoadVideo()
@@ -464,134 +408,11 @@ namespace Vocaluxe.Base
if (_Video != -1 || String.IsNullOrEmpty(_CurrentPlaylistElement.VideoFilePath))
return;
_Video = CVideo.Load(_CurrentPlaylistElement.VideoFilePath);
- if (_CurrentPlaylistElement.Start > 0.001 && CConfig.BackgroundMusicUseStart == EOffOn.TR_CONFIG_ON)
- CVideo.Skip(_Video, _CurrentPlaylistElement.Start, _CurrentPlaylistElement.VideoGap);
+ if (CConfig.BackgroundMusicUseStart == EOffOn.TR_CONFIG_ON)
+ CVideo.Skip(_Video, 0f, _CurrentPlaylistElement.VideoGap + _CurrentPlaylistElement.Start); //Use gap, otherwhise we will overwrite position in GetVideoTexture
else
CVideo.Skip(_Video, 0f, _CurrentPlaylistElement.VideoGap);
_VideoFading = new CFading(0f, 1f, 3f);
}
}
-
- class CPlaylistElement
- {
- private readonly CSong _Song;
-
- private readonly int _SongID;
- public int SongID
- {
- get { return _SongID; }
- }
-
- private string _MusicFilePath = String.Empty;
-
- public string MusicFilePath
- {
- get
- {
- if (_Song != null)
- return _Song.GetMP3();
-
- return _MusicFilePath;
- }
-
- set { _MusicFilePath = value; }
- }
-
- public string VideoFilePath
- {
- get
- {
- if (_Song != null)
- return _Song.GetVideo();
-
- return string.Empty;
- }
- }
-
- public string Title
- {
- get
- {
- if (_Song != null)
- return _Song.Title;
-
- return "";
- }
- }
-
- public string Artist
- {
- get
- {
- if (_Song != null)
- return _Song.Artist;
-
- return "";
- }
- }
-
- public float Start
- {
- get
- {
- if (_Song != null)
- return _Song.Start;
-
- return 0f;
- }
- }
-
- public float Finish
- {
- get
- {
- if (_Song != null)
- return _Song.Finish;
-
- return 0f;
- }
- }
-
- public CTexture Cover
- {
- get
- {
- if (_Song != null)
- return _Song.CoverTextureSmall;
-
- return CCover.NoCover;
- }
- }
-
- public float VideoGap
- {
- get
- {
- if (_Song != null)
- return _Song.VideoGap;
-
- return 0;
- }
- }
-
- public CPlaylistElement(CSong song)
- {
- MusicFilePath = string.Empty;
- _SongID = song.ID;
-
- _Song = song;
- }
-
- public CPlaylistElement(string filePath)
- {
- MusicFilePath = filePath;
- _SongID = -1;
- }
-
- public CPlaylistElement()
- {
- MusicFilePath = string.Empty;
- _SongID = -1;
- }
- }
}
\ No newline at end of file
diff --git a/Vocaluxe/Base/CConfig.cs b/Vocaluxe/Base/CConfig.cs
index 2b5d8b3d..6eb0be6b 100644
--- a/Vocaluxe/Base/CConfig.cs
+++ b/Vocaluxe/Base/CConfig.cs
@@ -24,7 +24,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml;
-using Vocaluxe.Lib.Sound;
+using Vocaluxe.Lib.Sound.Record;
using Vocaluxe.Lib.Webcam;
using VocaluxeLib;
using VocaluxeLib.Profile;
@@ -43,6 +43,15 @@ namespace Vocaluxe.Base
ConformanceLevel = ConformanceLevel.Document
};
+ private static bool _Initialized;
+
+ // Base file and folder names (formerly from CSettings but they can be changed)
+ private const string _FolderProfiles = "Profiles"; //Use ProfileFolders for access
+ private const string _FolderSongs = "Songs"; //Use SongFolders for access
+ public static string FolderPlaylists = "Playlists";
+ public static string FileHighscoreDB = "HighscoreDB.sqlite";
+ private static string _FileConfig = "Config.xml";
+
// Debug
public static EDebugLevel DebugLevel = EDebugLevel.TR_CONFIG_OFF;
public static EOffOn SaveModifiedSongs = EOffOn.TR_CONFIG_OFF;
@@ -87,7 +96,6 @@ namespace Vocaluxe.Base
// Sound
public static EPlaybackLib PlayBackLib = EPlaybackLib.Gstreamer;
- public static ERecordLib RecordLib = ERecordLib.PortAudio;
public static EBufferSize AudioBufferSize = EBufferSize.B2048;
public static int AudioLatency;
private static int _BackgroundMusicVolume = 30;
@@ -97,8 +105,28 @@ namespace Vocaluxe.Base
public static int PreviewMusicVolume = 50;
public static int GameMusicVolume = 80;
+ //Folders
+ public static readonly List SongFolders = new List()
+ {
+ Path.Combine(Directory.GetCurrentDirectory(), _FolderSongs)
+
+#if INSTALLER
+ ,Path.Combine(CSettings.DataPath, CSettings.FolderSongs);
+#endif
+ };
+ ///
+ /// Folders with profiles
+ /// First one is used for new profiles
+ ///
+ public static readonly List ProfileFolders = new List
+ {
+#if INSTALLER
+ Path.Combine(Environment.CurrentDirectory, CSettings.FolderProfiles),
+#endif
+ Path.Combine(CSettings.DataPath, _FolderProfiles)
+ };
+
// Game
- public static readonly List SongFolder = new List();
public static ESongMenu SongMenu = ESongMenu.TR_CONFIG_TILE_BOARD;
public static ESongSorting SongSorting = ESongSorting.TR_CONFIG_ARTIST;
public static EOffOn IgnoreArticles = EOffOn.TR_CONFIG_ON;
@@ -120,8 +148,11 @@ namespace Vocaluxe.Base
public static EOffOn VideosToBackground = EOffOn.TR_CONFIG_OFF;
// Record
- public static SMicConfig[] MicConfig;
- public static int MicDelay = 300; //[ms]
+ public static ERecordLib RecordLib = ERecordLib.PortAudio;
+ public static readonly SMicConfig[] MicConfig = new SMicConfig[CSettings.MaxNumPlayer];
+ public static int MicDelay = 200; //[ms]
+
+ // Webcam
public static EWebcamLib WebcamLib = EWebcamLib.OpenCV;
public static SWebcamConfig WebcamConfig;
@@ -135,8 +166,6 @@ namespace Vocaluxe.Base
private static readonly List _Params = new List();
private static readonly List _Values = new List();
- //Variables to save old values for commandline-parameters
- private static readonly List _SongFolderOld = new List();
public static int BackgroundMusicVolume
{
get { return _BackgroundMusicVolume; }
@@ -154,27 +183,21 @@ namespace Vocaluxe.Base
public static void Init()
{
- SongFolder.Add(Path.Combine(Directory.GetCurrentDirectory(), CSettings.FolderSongs));
-
-#if INSTALLER
- SongFolder.Add(Path.Combine(CSettings.DataPath, CSettings.FolderSongs));
-#endif
-
- foreach (string folder in SongFolder)
- CSettings.CreateFolder(folder);
-
- MicConfig = new SMicConfig[CSettings.MaxNumPlayer];
+ if (_Initialized)
+ return;
// Init config file
- if (!File.Exists(Path.Combine(CSettings.DataPath, CSettings.FileConfig)))
+ if (!File.Exists(Path.Combine(CSettings.DataPath, _FileConfig)))
SaveConfig();
+ else
+ _LoadConfig();
- _LoadConfig();
+ _Initialized = true;
}
private static void _LoadConfig()
{
- CXMLReader xmlReader = CXMLReader.OpenFile(Path.Combine(CSettings.DataPath, CSettings.FileConfig));
+ CXMLReader xmlReader = CXMLReader.OpenFile(Path.Combine(CSettings.DataPath, _FileConfig));
if (xmlReader == null)
return;
@@ -231,15 +254,14 @@ namespace Vocaluxe.Base
#region Game
// Songfolder
- string value = string.Empty;
+ string value = String.Empty;
int i = 1;
while (xmlReader.GetValue("//root/Game/SongFolder" + i, out value, value))
{
if (i == 1)
- SongFolder.Clear();
-
- SongFolder.Add(value);
- value = string.Empty;
+ SongFolders.Clear();
+ SongFolders.Add(value);
+ value = String.Empty;
i++;
}
@@ -271,7 +293,7 @@ namespace Vocaluxe.Base
//Read players from config
for (i = 1; i <= CSettings.MaxNumPlayer; i++)
- xmlReader.GetValue("//root/Game/Players/Player" + i, out Players[i - 1], string.Empty);
+ xmlReader.GetValue("//root/Game/Players/Player" + i, out Players[i - 1], String.Empty);
#endregion Game
#region Video
@@ -290,7 +312,6 @@ namespace Vocaluxe.Base
#endregion Video
#region Record
- MicConfig = new SMicConfig[CSettings.MaxNumPlayer];
for (int p = 1; p <= CSettings.MaxNumPlayer; p++)
{
MicConfig[p - 1] = new SMicConfig(0);
@@ -319,7 +340,7 @@ namespace Vocaluxe.Base
XmlWriter writer = null;
try
{
- writer = XmlWriter.Create(Path.Combine(CSettings.DataPath, CSettings.FileConfig), XMLSettings);
+ writer = XmlWriter.Create(Path.Combine(CSettings.DataPath, _FileConfig), XMLSettings);
writer.WriteStartDocument();
writer.WriteStartElement("root");
@@ -470,21 +491,9 @@ namespace Vocaluxe.Base
writer.WriteElementString("Language", Language);
// SongFolder
- // Check, if program was started with songfolder-parameters
- if (_SongFolderOld.Count > 0)
- {
- //Write "old" song-folders to config.
- writer.WriteComment("SongFolder: SongFolder1, SongFolder2, SongFolder3, ...");
- for (int i = 0; i < _SongFolderOld.Count; i++)
- writer.WriteElementString("SongFolder" + (i + 1), _SongFolderOld[i]);
- }
- else
- {
- //Write "normal" song-folders to config.
- writer.WriteComment("SongFolder: SongFolder1, SongFolder2, SongFolder3, ...");
- for (int i = 0; i < SongFolder.Count; i++)
- writer.WriteElementString("SongFolder" + (i + 1), SongFolder[i]);
- }
+ writer.WriteComment("SongFolder: SongFolder1, SongFolder2, SongFolder3, ...");
+ for (int i = 0; i < SongFolders.Count; i++)
+ writer.WriteElementString("SongFolder" + (i + 1), SongFolders[i]);
writer.WriteComment("SongMenu: " + CHelper.ListStrings(Enum.GetNames(typeof(ESongMenu))));
writer.WriteElementString("SongMenu", Enum.GetName(typeof(ESongMenu), SongMenu));
@@ -626,7 +635,7 @@ namespace Vocaluxe.Base
///
public static bool IsMicConfig()
{
- ReadOnlyCollection devices = CSound.RecordGetDevices();
+ ReadOnlyCollection devices = CRecord.GetDevices();
if (devices == null)
return false;
@@ -640,7 +649,7 @@ namespace Vocaluxe.Base
///
public static bool IsMicConfig(int player)
{
- ReadOnlyCollection devices = CSound.RecordGetDevices();
+ ReadOnlyCollection devices = CRecord.GetDevices();
if (devices == null)
return false;
@@ -666,8 +675,8 @@ namespace Vocaluxe.Base
public static bool AutoAssignMics()
{
//Look for (usb-)mic
- //SRecordDevice[] Devices = new SRecordDevice[CSound.RecordGetDevices().Length];
- ReadOnlyCollection devices = CSound.RecordGetDevices();
+ //SRecordDevice[] Devices = new SRecordDevice[CRecord.RecordGetDevices().Length];
+ ReadOnlyCollection devices = CRecord.GetDevices();
if (devices == null)
return false;
@@ -731,7 +740,7 @@ namespace Vocaluxe.Base
Regex spliterParam = new Regex(@"-{1,2}|\/", RegexOptions.IgnoreCase);
//Complete argument string
- string arguments = args.Aggregate(string.Empty, (current, arg) => current + (arg + " "));
+ string arguments = args.Aggregate(String.Empty, (current, arg) => current + arg + " ");
args = spliterParam.Split(arguments);
@@ -792,24 +801,22 @@ namespace Vocaluxe.Base
case "configfile":
//Check if value is valid
if (_CheckFile(value))
- CSettings.FileConfig = value;
+ _FileConfig = value;
break;
case "scorefile":
//Check if value is valid
if (_CheckFile(value))
- CSettings.FileHighscoreDB = value;
+ FileHighscoreDB = value;
break;
case "playlistfolder":
- CSettings.CreateFolder(value);
- CSettings.FolderPlaylists = value;
+ FolderPlaylists = value;
break;
case "profilefolder":
- CSettings.CreateFolder(value);
- CSettings.FoldersProfiles.Clear();
- CSettings.FoldersProfiles.Add(value);
+ ProfileFolders.Clear();
+ ProfileFolders.Add(value);
break;
}
}
@@ -820,6 +827,7 @@ namespace Vocaluxe.Base
///
public static void UseCommandLineParamsAfter()
{
+ bool songFoldersOverwritten = false;
//Check each parameter
for (int i = 0; i < _Params.Count; i++)
{
@@ -834,15 +842,13 @@ namespace Vocaluxe.Base
{
case "songfolder":
case "songpath":
- //Check if SongFolders from config.xml are saved
- if (_SongFolderOld.Count == 0)
+ if (!songFoldersOverwritten)
{
- _SongFolderOld.Clear();
- _SongFolderOld.AddRange(SongFolder);
- SongFolder.Clear();
+ SongFolders.Clear();
+ songFoldersOverwritten = true;
}
- //Add parameter-value to SongFolder
- SongFolder.Add(value);
+ if (!SongFolders.Contains(value))
+ SongFolders.Add(value);
break;
}
}
diff --git a/Vocaluxe/Base/CController.cs b/Vocaluxe/Base/CController.cs
index ce70f459..604b17c0 100644
--- a/Vocaluxe/Base/CController.cs
+++ b/Vocaluxe/Base/CController.cs
@@ -36,19 +36,26 @@ namespace Vocaluxe.Base
_KeysPool = new List();
_MousePool = new List();
- _Controller.Add(new CWiiMote());
- _Controller.Add(CVocaluxeServer.Controller);
+ _AddController(new CWiiMote());
+ _AddController(CVocaluxeServer.Controller);
+ }
- foreach (IController controller in _Controller)
- controller.Init();
+ private static void _AddController(IController controller)
+ {
+ if (controller.Init())
+ _Controller.Add(controller);
}
public static void Close()
{
- foreach (IController controller in _Controller)
- controller.Close();
-
- _Controller = new List();
+ if (_Controller != null)
+ {
+ foreach (IController controller in _Controller)
+ controller.Close();
+ _Controller = null;
+ _KeysPool = null;
+ _MousePool = null;
+ }
}
public static void Connect()
diff --git a/Vocaluxe/Base/CCover.cs b/Vocaluxe/Base/CCover.cs
index a156fa8b..fddf06d2 100644
--- a/Vocaluxe/Base/CCover.cs
+++ b/Vocaluxe/Base/CCover.cs
@@ -36,11 +36,9 @@ namespace Vocaluxe.Base
static class CCover
{
private static readonly XmlWriterSettings _Settings = new XmlWriterSettings();
- private static readonly Dictionary _Cover = new Dictionary();
+ private static readonly Dictionary _Covers = new Dictionary();
private static readonly List _CoverThemes = new List();
- private static readonly Object _MutexCover = new Object();
-
public static CTexture NoCover { get; private set; }
public static void Init()
@@ -87,24 +85,22 @@ namespace Vocaluxe.Base
///
public static CTexture Cover(string name)
{
- lock (_MutexCover)
+ lock (_Covers)
{
if (!_CoverExists(name))
return NoCover;
- return _Cover[name];
+ return _Covers[name];
}
}
///
/// Returns true if a cover with the given name exists.
+ /// MUST HOLD _Covers lock at this point
///
private static bool _CoverExists(string name)
{
- lock (_MutexCover)
- {
- return _Cover.ContainsKey(name);
- }
+ return _Covers.ContainsKey(name);
}
///
@@ -112,14 +108,15 @@ namespace Vocaluxe.Base
///
public static void ReloadCover()
{
- List keys = _Cover.Keys.ToList();
-
- foreach (string key in keys)
+ lock (_Covers)
{
- CTexture texture = _Cover[key];
- CDraw.RemoveTexture(ref texture);
+ foreach (string key in _Covers.Keys.ToList())
+ {
+ CTexture texture = _Covers[key];
+ CDraw.RemoveTexture(ref texture);
+ }
+ _Covers.Clear();
}
- _Cover.Clear();
_LoadCover(CConfig.CoverTheme);
}
@@ -178,12 +175,16 @@ namespace Vocaluxe.Base
return;
var ignoreList = new List();
+
+ string coverPath = Path.Combine(CSettings.FolderCover, coverTheme.Folder);
+ List files = CHelper.ListImageFiles(coverPath, true, true);
+
CXMLReader xmlReader = CXMLReader.OpenFile(Path.Combine(CSettings.FolderCover, coverTheme.File));
- if (xmlReader != null)
+ lock (_Covers)
{
- lock (_MutexCover)
+ if (xmlReader != null)
{
- _Cover.Clear();
+ _Covers.Clear();
List cover = xmlReader.GetValues("Cover");
foreach (string coverName in cover)
{
@@ -199,38 +200,36 @@ namespace Vocaluxe.Base
ignoreList.Add(Path.GetFileName(coverFilePath));
if (name == "NoCover")
- NoCover = _Cover[name];
+ NoCover = _Covers[name];
}
}
- }
-
- var files = new List();
-
- string coverPath = Path.Combine(CSettings.FolderCover, coverTheme.Folder);
- files.AddRange(CHelper.ListFiles(coverPath, "*.png", true, true));
- files.AddRange(CHelper.ListFiles(coverPath, "*.jpg", true, true));
- files.AddRange(CHelper.ListFiles(coverPath, "*.jpeg", true, true));
- files.AddRange(CHelper.ListFiles(coverPath, "*.bmp", true, true));
- foreach (string file in files)
- {
- if (!ignoreList.Contains(Path.GetFileName(file)))
- _AddCover(Path.GetFileNameWithoutExtension(file), file);
+ foreach (string file in files)
+ {
+ if (!ignoreList.Contains(Path.GetFileName(file)))
+ _AddCover(Path.GetFileNameWithoutExtension(file), file);
+ }
}
}
+ ///
+ /// Ads a cover with the given name if it does not exist yet
+ /// MUST HOLD _Covers lock at this point
+ ///
+ /// Name of the cover
+ /// Filename of image file
private static void _AddCover(string name, string file)
{
CTexture texture = CDraw.AddTexture(file);
if (!_CoverExists(name))
- _Cover.Add(name, texture);
+ _Covers.Add(name, texture);
else
{
- CTexture tex = _Cover[name];
+ CTexture tex = _Covers[name];
CDraw.RemoveTexture(ref tex);
- _Cover[name] = texture;
+ _Covers[name] = texture;
}
}
}
diff --git a/Vocaluxe/Base/CCursor.cs b/Vocaluxe/Base/CCursor.cs
index 94a1e495..ecb0738c 100644
--- a/Vocaluxe/Base/CCursor.cs
+++ b/Vocaluxe/Base/CCursor.cs
@@ -24,6 +24,7 @@ namespace Vocaluxe.Base
{
class CCursor
{
+ private int _MouseMoveDiffMin = CSettings.MouseMoveDiffMinActive;
private CFading _Fading;
private CTexture _Cursor;
@@ -49,12 +50,8 @@ namespace Vocaluxe.Base
public void Draw()
{
- if (_Movetimer.IsRunning && _Movetimer.ElapsedMilliseconds > CSettings.MouseMoveOffTime)
- {
- _Movetimer.Stop();
- _Fade(0f, 0.5f);
- }
-
+ if (_Movetimer.ElapsedMilliseconds > CSettings.MouseMoveOffTime)
+ Deactivate();
if (_Fading != null)
{
@@ -64,21 +61,15 @@ namespace Vocaluxe.Base
_Fading = null;
}
- if (Visible && (CSettings.GameState == EGameState.EditTheme || ShowCursor))
+ if (Visible && (CSettings.ProgramState == EProgramState.EditTheme || ShowCursor))
CDraw.DrawTexture(_Cursor);
}
public void UpdatePosition(int x, int y)
{
- if (Math.Abs(_Cursor.Rect.X - x) > CSettings.MouseMoveDiffMin ||
- Math.Abs(_Cursor.Rect.Y - y) > CSettings.MouseMoveDiffMin)
- {
- if (!IsActive)
- _Fade(1f, 0.2f);
-
- _Movetimer.Restart();
- CSettings.MouseActive();
- }
+ if (Math.Abs(_Cursor.Rect.X - x) > _MouseMoveDiffMin ||
+ Math.Abs(_Cursor.Rect.Y - y) > _MouseMoveDiffMin)
+ Activate();
_Cursor.Rect.X = x;
_Cursor.Rect.Y = y;
@@ -109,14 +100,20 @@ namespace Vocaluxe.Base
UpdatePosition(x, y);
}
- public void FadeOut()
+ public void Deactivate()
{
- _Movetimer.Stop();
+ if (!IsActive)
+ return;
+ _MouseMoveDiffMin = CSettings.MouseMoveDiffMinInactive;
+ _Movetimer.Reset();
_Fade(0f, 0.5f);
}
- public void FadeIn()
+ public void Activate()
{
+ if (IsActive)
+ return;
+ _MouseMoveDiffMin = CSettings.MouseMoveDiffMinActive;
_Movetimer.Restart();
_Fade(1f, 0.2f);
}
diff --git a/Vocaluxe/Base/CDataBase.cs b/Vocaluxe/Base/CDataBase.cs
index 888ea52d..3a512891 100644
--- a/Vocaluxe/Base/CDataBase.cs
+++ b/Vocaluxe/Base/CDataBase.cs
@@ -20,9 +20,13 @@ using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
-using System.Runtime.InteropServices;
using System.IO;
+using System.Runtime.InteropServices;
using System.Text;
+using Community.CsharpSqlite;
+using VocaluxeLib;
+using VocaluxeLib.Draw;
+using VocaluxeLib.Songs;
#if WIN
using System.Data.SQLite;
#else
@@ -32,10 +36,6 @@ using SQLiteTransaction = Mono.Data.Sqlite.SqliteTransaction;
using SQLiteCommand = Mono.Data.Sqlite.SqliteCommand;
using SQLiteDataReader = Mono.Data.Sqlite.SqliteDataReader;
#endif
-using Community.CsharpSqlite;
-using VocaluxeLib;
-using VocaluxeLib.Songs;
-using VocaluxeLib.Draw;
namespace Vocaluxe.Base
{
@@ -53,31 +53,37 @@ namespace Vocaluxe.Base
private static string _CoverFilePath;
private static string _CreditsRessourcesFilePath;
+ //You have to lock all actions using cover connection or transaction, otherwhise order is not guaranted
+ private static readonly object _CoverMutex = new object();
private static SQLiteConnection _ConnectionCover;
private static SQLiteTransaction _TransactionCover;
- public static void Init()
+ public static bool Init()
{
- _HighscoreFilePath = Path.Combine(Environment.CurrentDirectory, CSettings.FileHighscoreDB);
+ _HighscoreFilePath = Path.Combine(Environment.CurrentDirectory, CConfig.FileHighscoreDB);
_CoverFilePath = Path.Combine(Environment.CurrentDirectory, CSettings.FileCoverDB);
_CreditsRessourcesFilePath = Path.Combine(Environment.CurrentDirectory, CSettings.FileCreditsRessourcesDB);
- _InitHighscoreDB();
+ if (!_InitHighscoreDB())
+ {
+ CLog.LogError("Error initializing Highscore-DB", true, true);
+ return false;
+ }
if (!_InitCoverDB())
{
CLog.LogError("Error initializing Cover-DB", true, true);
- return;
+ return false;
}
if (!_InitCreditsRessourcesDB())
{
- CLog.LogError("Error initializing Cover-DB", true, true);
- return;
+ CLog.LogError("Error initializing Credits-DB", true, true);
+ return false;
}
- GC.Collect();
+ return true;
}
#region Highscores
- public static bool GetDataBaseSongInfos(string artist, string title, out int numPlayed, out string dateAdded, out int highscoreID)
+ public static bool GetDataBaseSongInfos(string artist, string title, out int numPlayed, out DateTime dateAdded, out int highscoreID)
{
string sArtist;
string sTitle;
@@ -378,12 +384,12 @@ namespace Vocaluxe.Base
return -1;
}
- private static bool _GetDataBaseSongInfos(int songID, out string artist, out string title, out int numPlayed, out string dateAdded, string filePath)
+ private static bool _GetDataBaseSongInfos(int songID, out string artist, out string title, out int numPlayed, out DateTime dateAdded, string filePath)
{
artist = String.Empty;
title = String.Empty;
numPlayed = 0;
- dateAdded = String.Empty;
+ dateAdded = DateTime.Today;
using (var connection = new SQLiteConnection())
{
@@ -419,7 +425,7 @@ namespace Vocaluxe.Base
artist = reader.GetString(0);
title = reader.GetString(1);
numPlayed = reader.GetInt32(2);
- dateAdded = new DateTime(reader.GetInt64(3)).ToString("dd/MM/yyyy");
+ dateAdded = new DateTime(reader.GetInt64(3));
reader.Dispose();
return true;
}
@@ -431,7 +437,7 @@ namespace Vocaluxe.Base
return false;
}
- private static void _InitHighscoreDB()
+ private static bool _InitHighscoreDB()
{
string oldDBFilePath = Path.Combine(Environment.CurrentDirectory, CSettings.FileOldHighscoreDB);
if (File.Exists(oldDBFilePath))
@@ -441,17 +447,17 @@ namespace Vocaluxe.Base
if (!_CreateOrConvert(oldDBFilePath))
{
CLog.LogError("Cannot init Highscore DB: Error opening database: " + oldDBFilePath, true, true);
- return;
+ return false;
}
if (!_CreateOrConvert(_HighscoreFilePath))
{
CLog.LogError("Cannot init Highscore DB: Error opening database: " + _HighscoreFilePath, true, true);
- return;
+ return false;
}
if (!_ImportData(oldDBFilePath))
{
CLog.LogError("Cannot init Highscore DB: Error importing data", true, true);
- return;
+ return false;
}
}
else
@@ -460,13 +466,17 @@ namespace Vocaluxe.Base
if (!_CreateOrConvert(_HighscoreFilePath))
{
CLog.LogError("Cannot init Highscore DB: Error opening database: " + _HighscoreFilePath, true, true);
- return;
+ return false;
}
}
File.Delete(oldDBFilePath);
}
else if (!_CreateOrConvert(_HighscoreFilePath))
+ {
CLog.LogError("Cannot init Highscore DB: Error opening database: " + _HighscoreFilePath, true, true);
+ return false;
+ }
+ return true;
}
private static void _CreateHighscoreDB(string filePath)
@@ -1026,7 +1036,8 @@ namespace Vocaluxe.Base
int shortsong = source.GetInt32(7);
int diff = source.GetInt32(8);
- string artist, title, dateadded;
+ string artist, title;
+ DateTime dateadded;
int numplayed;
if (_GetDataBaseSongInfos(songid, out artist, out title, out numplayed, out dateadded, sourceDBPath))
AddScore(player, score, linenr, date, medley, duet, shortsong, diff, artist, title, numplayed, _HighscoreFilePath);
@@ -1050,134 +1061,150 @@ namespace Vocaluxe.Base
return false;
}
- if (_ConnectionCover == null)
+ lock (_CoverMutex)
{
- _ConnectionCover = new SQLiteConnection {ConnectionString = "Data Source=" + _CoverFilePath};
- _ConnectionCover.Open();
- }
-
- using (var command = new SQLiteCommand(_ConnectionCover))
- {
- command.CommandText = "SELECT id, width, height FROM Cover WHERE [Path] = @path";
- command.Parameters.Add("@path", DbType.String, 0).Value = coverPath;
-
- SQLiteDataReader reader = command.ExecuteReader();
-
- if (reader != null && reader.HasRows)
+ if (_ConnectionCover == null)
{
- reader.Read();
- int id = reader.GetInt32(0);
- int w = reader.GetInt32(1);
- int h = reader.GetInt32(2);
- reader.Close();
-
- command.CommandText = "SELECT Data FROM CoverData WHERE CoverID = @id";
- command.Parameters.Add("@id", DbType.Int32).Value = id;
- reader = command.ExecuteReader();
-
- if (reader.HasRows)
- {
- reader.Read();
- byte[] data = _GetBytes(reader);
- reader.Dispose();
- tex = CDraw.EnqueueTexture(w, h, data);
- return true;
- }
+ _ConnectionCover = new SQLiteConnection {ConnectionString = "Data Source=" + _CoverFilePath};
+ _ConnectionCover.Open();
}
- else
+
+ using (var command = new SQLiteCommand(_ConnectionCover))
{
- if (reader != null)
- reader.Close();
-
- if (_TransactionCover == null)
- _TransactionCover = _ConnectionCover.BeginTransaction();
-
- Bitmap origin;
- try
- {
- origin = new Bitmap(coverPath);
- }
- catch (Exception)
- {
- CLog.LogError("Error loading Texture: " + coverPath);
- return false;
- }
-
- int w = maxSize;
- int h = maxSize;
- byte[] data;
-
- try
- {
- if (origin.Width >= origin.Height && origin.Width > w)
- h = (int)Math.Round((float)w / origin.Width * origin.Height);
- else if (origin.Height > origin.Width && origin.Height > h)
- w = (int)Math.Round((float)h / origin.Height * origin.Width);
-
- using (var bmp = new Bitmap(w, h))
- {
- using (Graphics g = Graphics.FromImage(bmp))
- g.DrawImage(origin, new Rectangle(0, 0, w, h));
-
- data = new byte[w * h * 4];
- BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
- Marshal.Copy(bmpData.Scan0, data, 0, w * h * 4);
- bmp.UnlockBits(bmpData);
- }
- }
- finally
- {
- origin.Dispose();
- }
-
- tex = CDraw.EnqueueTexture(w, h, data);
-
- command.CommandText = "INSERT INTO Cover (Path, width, height) VALUES (@path, @w, @h)";
- command.Parameters.Add("@w", DbType.Int32).Value = w;
- command.Parameters.Add("@h", DbType.Int32).Value = h;
+ command.CommandText = "SELECT id, width, height FROM Cover WHERE [Path] = @path";
command.Parameters.Add("@path", DbType.String, 0).Value = coverPath;
- command.ExecuteNonQuery();
- command.CommandText = "SELECT id FROM Cover WHERE [Path] = @path";
- command.Parameters.Add("@path", DbType.String, 0).Value = coverPath;
- reader = command.ExecuteReader();
+ SQLiteDataReader reader = command.ExecuteReader();
- if (reader != null)
+ if (reader != null && reader.HasRows)
{
reader.Read();
int id = reader.GetInt32(0);
- reader.Dispose();
- command.CommandText = "INSERT INTO CoverData (CoverID, Data) VALUES (@id, @data)";
+ int w = reader.GetInt32(1);
+ int h = reader.GetInt32(2);
+ reader.Close();
+
+ command.CommandText = "SELECT Data FROM CoverData WHERE CoverID = @id";
command.Parameters.Add("@id", DbType.Int32).Value = id;
- command.Parameters.Add("@data", DbType.Binary, 20).Value = data;
- command.ExecuteReader();
- return true;
+ reader = command.ExecuteReader();
+
+ if (reader.HasRows)
+ {
+ reader.Read();
+ byte[] data = _GetBytes(reader);
+ reader.Dispose();
+ tex = CDraw.EnqueueTexture(w, h, data);
+ return true;
+ }
+ }
+ else
+ {
+ if (reader != null)
+ reader.Close();
+
+ if (_TransactionCover == null)
+ _TransactionCover = _ConnectionCover.BeginTransaction();
+
+ Bitmap origin;
+ try
+ {
+ origin = new Bitmap(coverPath);
+ }
+ catch (Exception)
+ {
+ CLog.LogError("Error loading Texture: " + coverPath);
+ return false;
+ }
+
+ int w = maxSize;
+ int h = maxSize;
+ byte[] data;
+
+ try
+ {
+ if (origin.Width >= origin.Height && origin.Width > w)
+ h = (int)Math.Round((float)w / origin.Width * origin.Height);
+ else if (origin.Height > origin.Width && origin.Height > h)
+ w = (int)Math.Round((float)h / origin.Height * origin.Width);
+
+ using (var bmp = new Bitmap(w, h))
+ {
+ using (Graphics g = Graphics.FromImage(bmp))
+ g.DrawImage(origin, new Rectangle(0, 0, w, h));
+
+ data = new byte[w * h * 4];
+ BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
+ Marshal.Copy(bmpData.Scan0, data, 0, w * h * 4);
+ bmp.UnlockBits(bmpData);
+ }
+ }
+ finally
+ {
+ origin.Dispose();
+ }
+
+ tex = CDraw.EnqueueTexture(w, h, data);
+
+ command.CommandText = "INSERT INTO Cover (Path, width, height) VALUES (@path, @w, @h)";
+ command.Parameters.Add("@w", DbType.Int32).Value = w;
+ command.Parameters.Add("@h", DbType.Int32).Value = h;
+ command.Parameters.Add("@path", DbType.String, 0).Value = coverPath;
+ command.ExecuteNonQuery();
+
+ command.CommandText = "SELECT id FROM Cover WHERE [Path] = @path";
+ command.Parameters.Add("@path", DbType.String, 0).Value = coverPath;
+ reader = command.ExecuteReader();
+
+ if (reader != null)
+ {
+ reader.Read();
+ int id = reader.GetInt32(0);
+ reader.Dispose();
+ command.CommandText = "INSERT INTO CoverData (CoverID, Data) VALUES (@id, @data)";
+ command.Parameters.Add("@id", DbType.Int32).Value = id;
+ command.Parameters.Add("@data", DbType.Binary, 20).Value = data;
+ command.ExecuteReader();
+ return true;
+ }
}
}
}
-
return false;
}
public static void CommitCovers()
{
- if (_TransactionCover != null)
+ lock (_CoverMutex)
{
- _TransactionCover.Commit();
- _TransactionCover = null;
- GC.Collect();
+ _CommitCovers();
}
}
- public static void CloseConnections()
+ ///
+ /// You have to hold the CoverMutex when calling this!
+ ///
+ private static void _CommitCovers()
{
- CommitCovers();
-
- if (_ConnectionCover != null)
+ if (_TransactionCover != null)
{
- _ConnectionCover.Close();
- _ConnectionCover.Dispose();
- _ConnectionCover = null;
+ _TransactionCover.Commit();
+ _TransactionCover.Dispose();
+ _TransactionCover = null;
+ }
+ }
+
+ public static void Close()
+ {
+ //Do commit and close atomicly otherwhise we may loose changes
+ lock (_CoverMutex)
+ {
+ CommitCovers();
+
+ if (_ConnectionCover != null)
+ {
+ _ConnectionCover.Dispose();
+ _ConnectionCover = null;
+ }
}
}
diff --git a/Vocaluxe/Base/CDraw.cs b/Vocaluxe/Base/CDraw.cs
index e888cad3..f43d8542 100644
--- a/Vocaluxe/Base/CDraw.cs
+++ b/Vocaluxe/Base/CDraw.cs
@@ -28,8 +28,10 @@ namespace Vocaluxe.Base
{
private static IDraw _Draw;
- public static void InitDraw()
+ public static bool InitDraw()
{
+ if (_Draw != null)
+ return false;
switch (CConfig.Renderer)
{
case ERenderer.TR_CONFIG_SOFTWARE:
@@ -45,6 +47,7 @@ namespace Vocaluxe.Base
{
CLog.LogError(e.Message + " - Error in initializing of OpenGL. Please check whether" +
" your graphic card drivers are up to date.", true, true);
+ return false;
}
break;
@@ -59,6 +62,7 @@ namespace Vocaluxe.Base
CLog.LogError(e.Message + " - Error in initializing of Direct3D. Please check if " +
"your DirectX redistributables and graphic card drivers are up to date. You can " +
"download the DirectX runtimes at http://www.microsoft.com/download/en/details.aspx?id=8109", true, true);
+ return false;
}
break;
#endif
@@ -67,8 +71,7 @@ namespace Vocaluxe.Base
_Draw = new CDrawWinForm();
break;
}
- if (!_Draw.Init())
- CLog.LogError("Could not init drawing interface!", true, true);
+ return _Draw.Init();
}
public static void MainLoop()
@@ -79,8 +82,11 @@ namespace Vocaluxe.Base
public static void Unload()
{
- _Draw.Unload();
- _Draw = null;
+ if (_Draw != null)
+ {
+ _Draw.Unload();
+ _Draw = null;
+ }
}
public static int GetScreenWidth()
diff --git a/Vocaluxe/Base/CGame.cs b/Vocaluxe/Base/CGame.cs
index 009e585f..46df686f 100644
--- a/Vocaluxe/Base/CGame.cs
+++ b/Vocaluxe/Base/CGame.cs
@@ -15,6 +15,9 @@
// along with Vocaluxe. If not, see .
#endregion
+//Uncomment to make the engine hit every note
+//#define DEBUG_HIT
+
using System;
using System.Collections.Generic;
using Vocaluxe.SongQueue;
@@ -208,8 +211,6 @@ namespace Vocaluxe.Base
public static void UpdatePoints(float time)
{
- const bool DEBUG_HIT = false;
-
CSong song = _SongQueue.GetSong();
if (song == null)
@@ -224,7 +225,7 @@ namespace Vocaluxe.Base
MidRecordedBeat = -0.5f + GetBeatFromTime(time, song.BPM, song.Gap + CConfig.MicDelay / 1000f);
for (int p = 0; p < _NumPlayer; p++)
- CSound.AnalyzeBuffer(p);
+ CRecord.AnalyzeBuffer(p);
if (_LastEvalBeat >= RecordedBeat)
return;
@@ -270,10 +271,14 @@ namespace Vocaluxe.Base
if (line == lines.Length - 1 && beat == lines[line].LastNoteBeat)
Players[p].SongFinished = true;
- if (notes[note].PointsForBeat > 0 && (CSound.RecordToneValid(p) || DEBUG_HIT))
+ if (notes[note].PointsForBeat > 0 && (CRecord.ToneValid(p)
+#if DEBUG_HIT
+ || true
+#endif
+ ))
{
int tone = notes[note].Tone;
- int tonePlayer = CSound.RecordGetTone(p);
+ int tonePlayer = CRecord.GetTone(p);
while (tonePlayer - tone > 6)
tonePlayer -= 12;
@@ -281,8 +286,9 @@ namespace Vocaluxe.Base
while (tonePlayer - tone < -6)
tonePlayer += 12;
- if (DEBUG_HIT)
+#if DEBUG_HIT
tonePlayer = tone;
+#endif
Players[p].NoteDiff = Math.Abs(tone - tonePlayer);
bool hit = Players[p].NoteDiff <= (2 - (int)CProfiles.GetDifficulty(Players[p].ProfileID));
@@ -290,7 +296,7 @@ namespace Vocaluxe.Base
if (hit)
{
// valid
- //CSound.RecordSetTone(p, Tone);
+ //CRecord.RecordSetTone(p, Tone);
double points = (CSettings.MaxScore - CSettings.LinebonusScore) * (double)notes[note].PointsForBeat /
song.Notes.GetVoice(Players[p].VoiceNr).Points;
if (notes[note].Type == ENoteType.Golden)
diff --git a/Vocaluxe/Base/CGraphics.cs b/Vocaluxe/Base/CGraphics.cs
index 0966424a..06a28e45 100644
--- a/Vocaluxe/Base/CGraphics.cs
+++ b/Vocaluxe/Base/CGraphics.cs
@@ -61,10 +61,10 @@ namespace Vocaluxe.Base
}
#region public methods
- public static void InitGraphics()
+ public static void Init()
{
// Add Screens, must be the same order as in EScreens!
- CLog.StartBenchmark(1, "Build Screen List");
+ CLog.StartBenchmark("Build Screen List");
_Screens.Add(new CScreenTest());
_Screens.Add(new CScreenLoad());
@@ -91,7 +91,7 @@ namespace Vocaluxe.Base
_PopupScreens.Add(new CPopupScreenVolumeControl());
_PopupScreens.Add(new CPopupScreenServerQR());
- CLog.StopBenchmark(1, "Build Screen List");
+ CLog.StopBenchmark("Build Screen List");
_CurrentScreen = EScreens.ScreenLoad;
_NextScreen = EScreens.ScreenNull;
@@ -101,9 +101,9 @@ namespace Vocaluxe.Base
_GlobalAlpha = 1f;
_ZOffset = 0f;
- CLog.StartBenchmark(0, "Load Theme");
+ CLog.StartBenchmark("Load Theme");
LoadTheme();
- CLog.StopBenchmark(0, "Load Theme");
+ CLog.StopBenchmark("Load Theme");
}
public static void LoadTheme()
@@ -112,10 +112,10 @@ namespace Vocaluxe.Base
for (int i = 0; i < _Screens.Count; i++)
{
- CLog.StartBenchmark(1, "Load Theme " + Enum.GetNames(typeof(EScreens))[i]);
+ CLog.StartBenchmark("Load Theme " + Enum.GetNames(typeof(EScreens))[i]);
_Screens[i].Init();
_Screens[i].LoadTheme(CTheme.GetThemeScreensPath(-1));
- CLog.StopBenchmark(1, "Load Theme " + Enum.GetNames(typeof(EScreens))[i]);
+ CLog.StopBenchmark("Load Theme " + Enum.GetNames(typeof(EScreens))[i]);
}
foreach (IMenu popup in _PopupScreens)
@@ -178,7 +178,7 @@ namespace Vocaluxe.Base
if (CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_DYNAMIC && _CurrentScreen != EScreens.ScreenSing)
CSongs.LoadCover();
- if (CSettings.GameState != EGameState.EditTheme)
+ if (CSettings.ProgramState != EProgramState.EditTheme)
{
run &= _HandleInputs(keys, mouse);
run &= _Update();
@@ -236,8 +236,6 @@ namespace Vocaluxe.Base
_Screens[(int)_CurrentScreen].OnClose();
_CurrentScreen = _NextScreen;
_NextScreen = EScreens.ScreenNull;
- if (CBackgroundMusic.IsPlaying)
- CBackgroundMusic.Play();
_Screens[(int)_CurrentScreen].OnShowFinish();
_Screens[(int)_CurrentScreen].ProcessMouseMove(_Cursor.X, _Cursor.Y);
@@ -346,8 +344,7 @@ namespace Vocaluxe.Base
if (keyEvent.Key == Keys.Left || keyEvent.Key == Keys.Right || keyEvent.Key == Keys.Up || keyEvent.Key == Keys.Down || keyEvent.Key == Keys.NumPad0 ||
keyEvent.Key == Keys.D0)
{
- CSettings.MouseInactive();
- _Cursor.FadeOut();
+ _Cursor.Deactivate();
if (keyEvent.ModAlt && keyEvent.ModCtrl && keyEvent.ModShift)
{
@@ -431,7 +428,7 @@ namespace Vocaluxe.Base
else
{
CConfig.BackgroundMusicVolume += diff;
- CBackgroundMusic.ApplyVolume();
+ CBackgroundMusic.SetVolume(CConfig.BackgroundMusicVolume);
}
break;
@@ -442,7 +439,7 @@ namespace Vocaluxe.Base
default:
CConfig.BackgroundMusicVolume += diff;
- CBackgroundMusic.ApplyVolume();
+ CBackgroundMusic.SetVolume(CConfig.BackgroundMusicVolume);
break;
}
CConfig.SaveConfig();
@@ -453,14 +450,12 @@ namespace Vocaluxe.Base
ShowPopup(EPopupScreens.PopupVolumeControl);
_VolumePopupTimer.Restart();
}
-
- CBackgroundMusic.ApplyVolume();
}
if (keyEvent.ModShift && (keyEvent.Key == Keys.F1))
- CSettings.GameState = EGameState.EditTheme;
+ CSettings.ProgramState = EProgramState.EditTheme;
else if (keyEvent.ModAlt && (keyEvent.Key == Keys.Enter))
- CSettings.IsFullScreen = !CSettings.IsFullScreen;
+ CConfig.FullScreen = (CConfig.FullScreen == EOffOn.TR_CONFIG_ON) ? EOffOn.TR_CONFIG_OFF : EOffOn.TR_CONFIG_ON;
else if (keyEvent.ModAlt && (keyEvent.Key == Keys.P))
CDraw.MakeScreenShot();
else
@@ -488,10 +483,7 @@ namespace Vocaluxe.Base
mouseEvent = inputMouseEvent;
if (mouseEvent.Wheel != 0)
- {
- CSettings.MouseActive();
- _Cursor.FadeIn();
- }
+ _Cursor.Activate();
_UpdateMousePosition(mouseEvent.X, mouseEvent.Y);
@@ -554,11 +546,11 @@ namespace Vocaluxe.Base
{
if (keyEvent.ModShift && (keyEvent.Key == Keys.F1))
{
- CSettings.GameState = EGameState.Normal;
+ CSettings.ProgramState = EProgramState.Normal;
_Screens[(int)_CurrentScreen].NextInteraction();
}
else if (keyEvent.ModAlt && (keyEvent.Key == Keys.Enter))
- CSettings.IsFullScreen = !CSettings.IsFullScreen;
+ CConfig.FullScreen = (CConfig.FullScreen == EOffOn.TR_CONFIG_ON) ? EOffOn.TR_CONFIG_OFF : EOffOn.TR_CONFIG_ON;
else if (keyEvent.ModAlt && (keyEvent.Key == Keys.P))
CDraw.MakeScreenShot();
else
@@ -592,7 +584,7 @@ namespace Vocaluxe.Base
}
if (_VolumePopupTimer.IsRunning)
- _Cursor.FadeIn();
+ _Cursor.Activate();
if (_CurrentPopupScreen != EPopupScreens.NoPopup)
_PopupScreens[(int)_CurrentPopupScreen].UpdateGame();
@@ -616,10 +608,10 @@ namespace Vocaluxe.Base
if (CConfig.DebugLevel >= EDebugLevel.TR_CONFIG_LEVEL2)
{
- debugOutput.Add(CSound.RecordGetToneAbs(0).ToString(CLanguage.Translate("TR_DEBUG_TONE_ABS") + " P1: 00"));
- debugOutput.Add(CSound.RecordGetMaxVolume(0).ToString(CLanguage.Translate("TR_DEBUG_MAX_VOLUME") + " P1: 0.000"));
- debugOutput.Add(CSound.RecordGetToneAbs(1).ToString(CLanguage.Translate("TR_DEBUG_TONE_ABS") + " P2: 00"));
- debugOutput.Add(CSound.RecordGetMaxVolume(1).ToString(CLanguage.Translate("TR_DEBUG_MAX_VOLUME") + " P2: 0.000"));
+ debugOutput.Add(CRecord.GetToneAbs(0).ToString(CLanguage.Translate("TR_DEBUG_TONE_ABS") + " P1: 00"));
+ debugOutput.Add(CRecord.GetMaxVolume(0).ToString(CLanguage.Translate("TR_DEBUG_MAX_VOLUME") + " P1: 0.000"));
+ debugOutput.Add(CRecord.GetToneAbs(1).ToString(CLanguage.Translate("TR_DEBUG_TONE_ABS") + " P2: 00"));
+ debugOutput.Add(CRecord.GetMaxVolume(1).ToString(CLanguage.Translate("TR_DEBUG_MAX_VOLUME") + " P2: 0.000"));
if (CConfig.DebugLevel >= EDebugLevel.TR_CONFIG_LEVEL3)
{
diff --git a/Vocaluxe/Base/CLog.cs b/Vocaluxe/Base/CLog.cs
index 8afe6cd4..a0484670 100644
--- a/Vocaluxe/Base/CLog.cs
+++ b/Vocaluxe/Base/CLog.cs
@@ -103,6 +103,8 @@ namespace Vocaluxe.Base
static class CLog
{
private const int _MaxBenchmarks = 10;
+ private static int _BenchmarksRunning;
+ private static bool _Initialized;
private static CLogFile _ErrorLog;
private static CLogFile _PerformanceLog;
@@ -124,15 +126,26 @@ namespace Vocaluxe.Base
_BenchmarkTimer = new Stopwatch[_MaxBenchmarks];
for (int i = 0; i < _BenchmarkTimer.Length; i++)
_BenchmarkTimer[i] = new Stopwatch();
+ _BenchmarksRunning = 0;
+ _Initialized = true;
}
public static void CloseAll()
{
- _ErrorLog.Close();
- _PerformanceLog.Close();
- _BenchmarkLog.Close();
- _DebugLog.Close();
- _SongInfoLog.Close();
+ if (_Initialized)
+ {
+ _ErrorLog.Dispose();
+ _ErrorLog = null;
+ _PerformanceLog.Dispose();
+ _PerformanceLog = null;
+ _BenchmarkLog.Dispose();
+ _BenchmarkLog = null;
+ _DebugLog.Dispose();
+ _DebugLog = null;
+ _SongInfoLog.Dispose();
+ _SongInfoLog = null;
+ _Initialized = false;
+ }
}
#region LogError
@@ -165,41 +178,44 @@ namespace Vocaluxe.Base
}
#region LogBenchmark
- public static void StartBenchmark(int benchmarkNr, string text)
+ public static void StartBenchmark(string text)
{
- if (benchmarkNr >= 0 && benchmarkNr < _MaxBenchmarks)
+ if (_BenchmarksRunning < _MaxBenchmarks)
{
- _BenchmarkTimer[benchmarkNr].Stop();
- _BenchmarkTimer[benchmarkNr].Reset();
-
string space = String.Empty;
- for (int i = 0; i < benchmarkNr; i++)
+ for (int i = 0; i < _BenchmarksRunning; i++)
space += " ";
_BenchmarkLog.Add(space + "Start " + text);
- _BenchmarkTimer[benchmarkNr].Start();
+ _BenchmarkTimer[_BenchmarksRunning].Restart();
}
+ else
+ LogError("Tried to start to many benchmarks at once"); //Log and ignore
+ _BenchmarksRunning++; //Inc even if not started to correct right Stop() call
}
- public static void StopBenchmark(int benchmarkNr, string text)
+ public static void StopBenchmark(string text)
{
- if (benchmarkNr >= 0 && benchmarkNr < _MaxBenchmarks)
+ if (_BenchmarksRunning > 0 && _BenchmarksRunning <= _MaxBenchmarks)
{
- _BenchmarkTimer[benchmarkNr].Stop();
+ _BenchmarksRunning--;
+ _BenchmarkTimer[_BenchmarksRunning].Stop();
string space = String.Empty;
- for (int i = 0; i < benchmarkNr; i++)
+ for (int i = 0; i < _BenchmarksRunning; i++)
space += " ";
float ms;
if (Stopwatch.IsHighResolution && _NanosecPerTick > 0)
- ms = (float)((_NanosecPerTick * _BenchmarkTimer[benchmarkNr].ElapsedTicks) / (1000.0 * 1000.0));
+ ms = (float)((_NanosecPerTick * _BenchmarkTimer[_BenchmarksRunning].ElapsedTicks) / (1000.0 * 1000.0));
else
- ms = _BenchmarkTimer[benchmarkNr].ElapsedMilliseconds;
+ ms = _BenchmarkTimer[_BenchmarksRunning].ElapsedMilliseconds;
_BenchmarkLog.Add(space + "Stop " + text + ", Elapsed Time: " + ms.ToString("0.000") + "ms");
_BenchmarkLog.Add(String.Empty);
}
+ else
+ _BenchmarksRunning--;
}
#endregion LogBenchmark
}
diff --git a/Vocaluxe/Base/CMain.cs b/Vocaluxe/Base/CMain.cs
index e0f02c3d..a66a960d 100644
--- a/Vocaluxe/Base/CMain.cs
+++ b/Vocaluxe/Base/CMain.cs
@@ -118,7 +118,7 @@ namespace Vocaluxe.Base
public IEnumerable GetSongFolders()
{
- return CConfig.SongFolder;
+ return CConfig.SongFolders;
}
public ESongSorting GetSongSorting()
@@ -179,9 +179,9 @@ namespace Vocaluxe.Base
return CSettings.ZNear;
}
- public EGameState GetGameState()
+ public EProgramState GetProgramState()
{
- return CSettings.GameState;
+ return CSettings.ProgramState;
}
public int GetToneMin()
@@ -226,7 +226,7 @@ namespace Vocaluxe.Base
public string GetFolderProfiles()
{
- return CSettings.FolderProfiles;
+ return CConfig.ProfileFolders[0];
}
public string GetDataPath()
@@ -360,11 +360,6 @@ namespace Vocaluxe.Base
CBackgroundMusic.Play();
}
- public void ApplyVolume()
- {
- CBackgroundMusic.ApplyVolume();
- }
-
public CTexture GetVideoTexture()
{
return CBackgroundMusic.GetVideoTexture();
@@ -606,6 +601,11 @@ namespace Vocaluxe.Base
return CProfiles.GetAvatarTextureFromProfile(profileID);
}
+ public CAvatar GetAvatarByFilename(string fileName)
+ {
+ return CProfiles.GetAvatarByFilename(fileName);
+ }
+
public bool IsProfileIDValid(int profileID)
{
return CProfiles.IsProfileIDValid(profileID);
@@ -626,7 +626,7 @@ namespace Vocaluxe.Base
{
public int GetToneAbs(int playerNr)
{
- return CSound.RecordGetToneAbs(playerNr);
+ return CRecord.GetToneAbs(playerNr);
}
}
@@ -839,7 +839,7 @@ namespace Vocaluxe.Base
return CDataBase.GetCover(fileName, ref texture, coverSize);
}
- public bool GetDataBaseSongInfos(string artist, string title, out int numPlayed, out string dateAdded, out int highscoreID)
+ public bool GetDataBaseSongInfos(string artist, string title, out int numPlayed, out DateTime dateAdded, out int highscoreID)
{
return CDataBase.GetDataBaseSongInfos(artist, title, out numPlayed, out dateAdded, out highscoreID);
}
diff --git a/Vocaluxe/Base/CParty.cs b/Vocaluxe/Base/CParty.cs
index 5735786f..a52c0c60 100644
--- a/Vocaluxe/Base/CParty.cs
+++ b/Vocaluxe/Base/CParty.cs
@@ -223,6 +223,7 @@ namespace Vocaluxe.Base
foreach (string file in files)
{
SPartyMode pm = _LoadPartyMode(file);
+ if(pm.NoErrors)
_PartyModes.Add(pm.PartyModeID, pm);
}
}
diff --git a/Vocaluxe/Base/CPlaylistElement.cs b/Vocaluxe/Base/CPlaylistElement.cs
new file mode 100644
index 00000000..195be8e7
--- /dev/null
+++ b/Vocaluxe/Base/CPlaylistElement.cs
@@ -0,0 +1,67 @@
+using System;
+using VocaluxeLib.Draw;
+using VocaluxeLib.Songs;
+
+namespace Vocaluxe.Base
+{
+ class CPlaylistElement
+ {
+ private readonly CSong _Song;
+ private readonly string _MusicFilePath = String.Empty;
+
+ public int SongID
+ {
+ get { return (_Song == null) ? -1 : _Song.ID; }
+ }
+
+ public string MusicFilePath
+ {
+ get { return _Song != null ? _Song.GetMP3() : _MusicFilePath; }
+ }
+
+ public string VideoFilePath
+ {
+ get { return _Song != null ? _Song.GetVideo() : string.Empty; }
+ }
+
+ public string Title
+ {
+ get { return _Song != null ? _Song.Title : ""; }
+ }
+
+ public string Artist
+ {
+ get { return _Song != null ? _Song.Artist : ""; }
+ }
+
+ public float Start
+ {
+ get { return _Song != null ? _Song.Start : 0f; }
+ }
+
+ public float Finish
+ {
+ get { return _Song != null ? _Song.Finish : 0f; }
+ }
+
+ public CTexture Cover
+ {
+ get { return _Song != null ? _Song.CoverTextureSmall : CCover.NoCover; }
+ }
+
+ public float VideoGap
+ {
+ get { return _Song != null ? _Song.VideoGap : 0; }
+ }
+
+ public CPlaylistElement(CSong song)
+ {
+ _Song = song;
+ }
+
+ public CPlaylistElement(string filePath)
+ {
+ _MusicFilePath = filePath;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Vocaluxe/Base/CPlaylists.cs b/Vocaluxe/Base/CPlaylists.cs
index e73dbd2b..5d928c7c 100644
--- a/Vocaluxe/Base/CPlaylists.cs
+++ b/Vocaluxe/Base/CPlaylists.cs
@@ -58,7 +58,7 @@ namespace Vocaluxe.Base
private static void _ConvertUSDXPlaylists()
{
var files = new List();
- files.AddRange(CHelper.ListFiles(Path.Combine(CSettings.DataPath, CSettings.FolderPlaylists), "*.upl", true, true));
+ files.AddRange(CHelper.ListFiles(Path.Combine(CSettings.DataPath, CConfig.FolderPlaylists), "*.upl", true, true));
foreach (string file in files)
{
@@ -73,7 +73,7 @@ namespace Vocaluxe.Base
_Playlists = new List();
var files = new List();
- files.AddRange(CHelper.ListFiles(Path.Combine(CSettings.DataPath, CSettings.FolderPlaylists), "*.xml", true, true));
+ files.AddRange(CHelper.ListFiles(Path.Combine(CSettings.DataPath, CConfig.FolderPlaylists), "*.xml", true, true));
foreach (string file in files)
{
diff --git a/Vocaluxe/Base/CProfiles.cs b/Vocaluxe/Base/CProfiles.cs
index b4f4ae50..8c5c9887 100644
--- a/Vocaluxe/Base/CProfiles.cs
+++ b/Vocaluxe/Base/CProfiles.cs
@@ -17,10 +17,11 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.IO;
using VocaluxeLib;
-using VocaluxeLib.Profile;
using VocaluxeLib.Draw;
+using VocaluxeLib.Profile;
namespace Vocaluxe.Base
{
@@ -111,13 +112,21 @@ namespace Vocaluxe.Base
break;
case EAction.AddProfile:
- if (change.Profile == null)
+ CProfile newProf = change.Profile;
+ if (newProf == null)
break;
- change.Profile.ID = _ProfileIDs.Dequeue();
- change.Profile.Avatar = _GetAvatar(change.Profile.AvatarFileName);
- change.Profile.SaveProfile();
- _Profiles.Add(change.Profile.ID, change.Profile);
+ newProf.ID = _ProfileIDs.Dequeue();
+ if (newProf.Avatar == null)
+ newProf.Avatar = _Avatars.Values.First();
+ else if (newProf.Avatar.ID < 0)
+ {
+ newProf.Avatar.ID = _AvatarIDs.Dequeue();
+ _Avatars.Add(newProf.Avatar.ID, newProf.Avatar);
+ _AvatarsChanged = true;
+ }
+ newProf.SaveProfile();
+ _Profiles.Add(newProf.ID, newProf);
_ProfilesChanged = true;
break;
@@ -318,7 +327,7 @@ namespace Vocaluxe.Base
{
var profile = new CProfile
{
- FileName = fileName != "" ? Path.Combine(CSettings.DataPath, CSettings.FolderProfiles, fileName) : String.Empty
+ FileName = fileName != "" ? Path.Combine(CConfig.ProfileFolders[0], fileName) : String.Empty
};
if (File.Exists(profile.FileName))
@@ -332,8 +341,8 @@ namespace Vocaluxe.Base
public static int NewAvatar(string fileName)
{
- var avatar = new CAvatar(-1);
- if (!avatar.LoadFromFile(fileName))
+ CAvatar avatar = CAvatar.GetAvatar(fileName);
+ if (avatar == null)
return -1;
avatar.ID = _AvatarIDs.Dequeue();
@@ -474,7 +483,7 @@ namespace Vocaluxe.Base
public static int GetAvatarID(int profileID)
{
- if (!IsProfileIDValid(profileID))
+ if (!IsProfileIDValid(profileID) || _Profiles[profileID].Avatar == null)
return -1;
return _Profiles[profileID].Avatar.ID;
@@ -505,7 +514,7 @@ namespace Vocaluxe.Base
public static CTexture GetAvatarTextureFromProfile(int profileID)
{
- if (!IsProfileIDValid(profileID))
+ if (!IsProfileIDValid(profileID) || _Profiles[profileID].Avatar == null)
return null;
return _Profiles[profileID].Avatar.Texture;
@@ -525,10 +534,7 @@ namespace Vocaluxe.Base
foreach (int id in ids)
{
if (_Profiles[id].LoadProfile())
- {
- _Profiles[id].Avatar = _GetAvatar(_Profiles[id].AvatarFileName);
knownFiles.Add(Path.GetFileName(_Profiles[id].FileName));
- }
else
_Profiles.Remove(id);
}
@@ -536,7 +542,7 @@ namespace Vocaluxe.Base
var files = new List();
- foreach (string path in CSettings.FoldersProfiles)
+ foreach (string path in CConfig.ProfileFolders)
files.AddRange(CHelper.ListFiles(path, "*.xml", true, true));
foreach (string file in files)
@@ -552,7 +558,6 @@ namespace Vocaluxe.Base
if (profile.LoadProfile())
{
- profile.Avatar = _GetAvatar(profile.AvatarFileName);
profile.ID = _ProfileIDs.Dequeue();
_Profiles.Add(profile.ID, profile);
}
@@ -577,21 +582,16 @@ namespace Vocaluxe.Base
}
var files = new List();
- foreach (string path in CSettings.FoldersProfiles)
- {
- files.AddRange(CHelper.ListFiles(path, "*.png", true, true));
- files.AddRange(CHelper.ListFiles(path, "*.jpg", true, true));
- files.AddRange(CHelper.ListFiles(path, "*.jpeg", true, true));
- files.AddRange(CHelper.ListFiles(path, "*.bmp", true, true));
- }
+ foreach (string path in CConfig.ProfileFolders)
+ files.AddRange(CHelper.ListImageFiles(path, true, true));
foreach (string file in files)
{
if (knownFiles.Contains(Path.GetFileName(file)))
continue;
- var avatar = new CAvatar(-1);
- if (avatar.LoadFromFile(file))
+ CAvatar avatar = CAvatar.GetAvatar(file);
+ if (avatar != null)
{
avatar.ID = _AvatarIDs.Dequeue();
_Avatars.Add(avatar.ID, avatar);
@@ -655,7 +655,7 @@ namespace Vocaluxe.Base
return String.CompareOrdinal(a.PlayerName, b.PlayerName);
}
- private static CAvatar _GetAvatar(string fileName)
+ public static CAvatar GetAvatarByFilename(string fileName)
{
string name = Path.GetFileName(fileName);
@@ -664,7 +664,7 @@ namespace Vocaluxe.Base
if (Path.GetFileName(_Avatars[id].FileName) == name)
return _Avatars[id];
}
- return new CAvatar(-1);
+ return null;
}
#endregion private methods
}
diff --git a/Vocaluxe/Base/CRecord.cs b/Vocaluxe/Base/CRecord.cs
new file mode 100644
index 00000000..5af44fd1
--- /dev/null
+++ b/Vocaluxe/Base/CRecord.cs
@@ -0,0 +1,122 @@
+using System.Collections.ObjectModel;
+using Vocaluxe.Lib.Sound.Record;
+using Vocaluxe.Lib.Sound.Record.DirectSound;
+using Vocaluxe.Lib.Sound.Record.PortAudio;
+using VocaluxeLib;
+
+namespace Vocaluxe.Base
+{
+ static class CRecord
+ {
+ private static IRecord _Record;
+
+ public static bool Init()
+ {
+ if (_Record != null)
+ return false;
+ switch (CConfig.RecordLib)
+ {
+#if WIN
+ case ERecordLib.DirectSound:
+ _Record = new CDirectSoundRecord();
+ break;
+#endif
+
+ // case ERecordLib.PortAudio:
+ default:
+ _Record = new CPortAudioRecord();
+ break;
+ }
+ return _Record.Init();
+ }
+
+ public static void Close()
+ {
+ if (_Record != null)
+ {
+ _Record.Close();
+ _Record = null;
+ }
+ }
+
+ public static bool Start()
+ {
+ return _Record.Start();
+ }
+
+ public static bool Stop()
+ {
+ return _Record.Stop();
+ }
+
+ public static void AnalyzeBuffer(int player)
+ {
+ _Record.AnalyzeBuffer(player);
+ }
+
+ public static int GetToneAbs(int player)
+ {
+ return _Record.GetToneAbs(player);
+ }
+
+ public static int GetTone(int player)
+ {
+ return _Record.GetTone(player);
+ }
+
+ public static void SetTone(int player, int tone)
+ {
+ _Record.SetTone(player, tone);
+ }
+
+ public static bool ToneValid(int player)
+ {
+ return _Record.ToneValid(player);
+ }
+
+ public static float GetMaxVolume(int player)
+ {
+ return _Record.GetMaxVolume(player);
+ }
+
+ public static int NumHalfTones(int player)
+ {
+ return _Record.NumHalfTones();
+ }
+
+ public static float[] ToneWeigth(int player)
+ {
+ return _Record.ToneWeigth(player);
+ }
+
+ public static ReadOnlyCollection GetDevices()
+ {
+ ReadOnlyCollection devices = _Record.RecordDevices();
+
+ if (devices != null)
+ {
+ foreach (CRecordDevice device in devices)
+ {
+ device.PlayerChannel1 = _GetPlayerFromMicConfig(device.Name, device.Driver, 1);
+ device.PlayerChannel2 = _GetPlayerFromMicConfig(device.Name, device.Driver, 2);
+ }
+ return devices;
+ }
+
+ return null;
+ }
+
+ private static int _GetPlayerFromMicConfig(string device, string devicedriver, int channel)
+ {
+ for (int p = 0; p < CSettings.MaxNumPlayer; p++)
+ {
+ if (CConfig.MicConfig[p].Channel != 0 &&
+ CConfig.MicConfig[p].DeviceName == device &&
+ CConfig.MicConfig[p].DeviceDriver == devicedriver &&
+ CConfig.MicConfig[p].Channel == channel)
+ return p + 1;
+ }
+ return 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Vocaluxe/Base/CSettings.cs b/Vocaluxe/Base/CSettings.cs
index e978691d..7c57abf1 100644
--- a/Vocaluxe/Base/CSettings.cs
+++ b/Vocaluxe/Base/CSettings.cs
@@ -33,6 +33,10 @@ namespace Vocaluxe.Base
// ReSharper restore UnusedMember.Global
}
+ ///
+ /// This class contains settings for the program
+ /// These are not editable, everything that can be changed by the user is in CConfig
+ ///
static class CSettings
{
#if ARCH_X86
@@ -43,7 +47,9 @@ namespace Vocaluxe.Base
private const String _Arch = "x64";
#endif
- public static EGameState GameState = EGameState.Start;
+ //TODO: This should not be here as it can change
+ //State of the program
+ public static EProgramState ProgramState = EProgramState.Start;
//Adjusting of programName and version now in the assembly config.
//I'd use the major and minor for Main releases, build number for every public release and revision for every bugfix version without any features
@@ -63,23 +69,20 @@ namespace Vocaluxe.Base
public const int ZNear = -100;
public const int ZFar = 100;
- public static bool IsFullScreen;
public const int VertexBufferElements = 10000;
#if INSTALLER
- public static string DataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Vocaluxe");
+ public static readonly string DataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Vocaluxe");
#else
- public static string DataPath = Environment.CurrentDirectory;
+ public static readonly string DataPath = Environment.CurrentDirectory;
#endif
public const string Icon = "Vocaluxe.ico";
public const string Logo = "Logo.png";
public const string FallbackLanguage = "English";
- public static string FileConfig = "Config.xml";
public const string FileFonts = "Fonts.xml";
public const string FileOldHighscoreDB = "Ultrastar.db";
- public static string FileHighscoreDB = "HighscoreDB.sqlite";
public const string FileCoverDB = "CoverDB.sqlite";
public const string FileCreditsRessourcesDB = "CreditsRessourcesDB.sqlite";
public const string FilePerformanceLog = "Performance.log";
@@ -96,21 +99,11 @@ namespace Vocaluxe.Base
public const string FolderThemes = "Themes";
public const string FolderThemeFonts = "Fonts";
public const string FolderScreens = "Screens";
- public const string FolderProfiles = "Profiles";
- public static List FoldersProfiles = new List
- {
-#if INSTALLER
- Path.Combine(Environment.CurrentDirectory, FolderProfiles),
-#endif
- Path.Combine(DataPath, FolderProfiles)
- };
public const string FolderPhotos = "Photos";
- public const string FolderSongs = "Songs";
public const string FolderSounds = "Sounds";
public const string FolderLanguages = "Languages";
public const string FolderScreenshots = "Screenshots";
public const string FolderBackgroundMusic = "BackgroundMusic";
- public static string FolderPlaylists = "Playlists";
public const string FolderPartyModes = "PartyModes";
public const string FolderPartyModeCode = "Code";
@@ -128,8 +121,10 @@ namespace Vocaluxe.Base
public const int ToneMax = 89;
public const int NumNoteLines = 11;
- public static int MouseMoveDiffMin = 2;
+
public const int MouseMoveOffTime = 3000; //in ms
+ public const int MouseMoveDiffMinActive = 3;
+ public const int MouseMoveDiffMinInactive = 15;
public const int MaxNumPlayer = 6;
public const int MaxScore = 10000;
@@ -153,14 +148,6 @@ namespace Vocaluxe.Base
public const float SlideShowImageTime = 3500f;
public const float SlideShowFadeTime = 500f;
- public static readonly List MusicFileTypes = new List
- {
- "*.mp3",
- "*.wma",
- "*.ogg",
- "*.wav"
- };
-
private static AssemblyName _Assembly
{
get { return Assembly.GetExecutingAssembly().GetName(); }
@@ -220,40 +207,37 @@ namespace Vocaluxe.Base
return RenderW / (float)RenderH;
}
- public static void MouseInactive()
- {
- MouseMoveDiffMin = 15;
- }
-
- public static void MouseActive()
- {
- MouseMoveDiffMin = 3;
- }
-
public static void CreateFolders()
{
var folders = new List
{
- FolderCover,
- FolderFonts,
+ Path.Combine(Environment.CurrentDirectory, FolderCover),
+ Path.Combine(Environment.CurrentDirectory, FolderFonts),
Path.Combine(DataPath, FolderScreenshots),
- FolderBackgroundMusic,
- FolderSounds,
- Path.Combine(DataPath, FolderPlaylists)
+ Path.Combine(Environment.CurrentDirectory, FolderBackgroundMusic),
+ Path.Combine(Environment.CurrentDirectory, FolderSounds),
+ Path.Combine(DataPath, CConfig.FolderPlaylists)
};
- folders.AddRange(FoldersProfiles);
+ folders.AddRange(CConfig.ProfileFolders);
+ folders.AddRange(CConfig.SongFolders);
foreach (string folder in folders)
- {
- string path = Path.Combine(Environment.CurrentDirectory, folder);
- CreateFolder(path);
- }
+ _CreateFolder(folder);
}
- public static void CreateFolder(string path)
+ private static void _CreateFolder(string path)
{
if (!Directory.Exists(path))
- Directory.CreateDirectory(path);
+ {
+ try
+ {
+ Directory.CreateDirectory(path);
+ }
+ catch (Exception e)
+ {
+ CLog.LogError("Cannot create directory \"" + path + "\": " + e.Message);
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/Vocaluxe/Base/CSongCategorizer.cs b/Vocaluxe/Base/CSongCategorizer.cs
index 74784cc2..8c68e615 100644
--- a/Vocaluxe/Base/CSongCategorizer.cs
+++ b/Vocaluxe/Base/CSongCategorizer.cs
@@ -17,7 +17,7 @@
using System;
using System.Collections.Generic;
-using System.Text;
+using System.Diagnostics;
using VocaluxeLib;
using VocaluxeLib.Songs;
@@ -61,36 +61,10 @@ namespace Vocaluxe.Base
_SetChanged();
}
- private void _CreateCategoriesLetter()
+ private void _CreateCategories()
{
- CCategory lastCategory = null;
- CCategory notLetterCat = null;
- foreach (CSongPointer songPointer in CSongs.Sorter.SortedSongs)
- {
- Char firstLetter = Char.ToUpper(songPointer.SortString.Normalize(NormalizationForm.FormD)[0]);
- if (Char.IsLetter(firstLetter))
- {
- if (lastCategory == null || firstLetter.ToString() != lastCategory.Name)
- {
- lastCategory = new CCategory(firstLetter.ToString());
- _Categories.Add(lastCategory);
- }
- lastCategory.Songs.Add(songPointer);
- }
- else
- {
- if (notLetterCat == null)
- {
- notLetterCat = new CCategory("#");
- _Categories.Add(notLetterCat);
- }
- notLetterCat.Songs.Add(songPointer);
- }
- }
- }
+ _AdjustCategoryNames();
- private void _CreateCategoriesNormal(string noCategoryName)
- {
CCategory lastCategory = null;
CCategory noCategory = null;
foreach (CSongPointer songPointer in CSongs.Sorter.SortedSongs)
@@ -108,7 +82,7 @@ namespace Vocaluxe.Base
{
if (noCategory == null)
{
- noCategory = new CCategory(noCategoryName);
+ noCategory = new CCategory(_GetNoCategoryName());
_Categories.Add(noCategory);
}
noCategory.Songs.Add(songPointer);
@@ -116,37 +90,15 @@ namespace Vocaluxe.Base
}
}
- private void _CreateCategories()
+ ///
+ /// Sets the SortStrings of the songpointers to the actual category names
+ ///
+ private static void _AdjustCategoryNames()
{
- string noCategoryName = "";
-
ESongSorting sorting = CSongs.Sorter.SongSorting;
-
switch (sorting)
{
- case ESongSorting.TR_CONFIG_EDITION:
- noCategoryName = CLanguage.Translate("TR_SCREENSONG_NOEDITION");
- break;
- case ESongSorting.TR_CONFIG_GENRE:
- noCategoryName = CLanguage.Translate("TR_SCREENSONG_NOGENRE");
- break;
case ESongSorting.TR_CONFIG_DECADE:
- case ESongSorting.TR_CONFIG_YEAR:
- noCategoryName = CLanguage.Translate("TR_SCREENSONG_NOYEAR");
- break;
- case ESongSorting.TR_CONFIG_LANGUAGE:
- noCategoryName = CLanguage.Translate("TR_SCREENSONG_NOLANGUAGE");
- break;
- case ESongSorting.TR_CONFIG_NONE:
- noCategoryName = CLanguage.Translate("TR_SCREENSONG_ALLSONGS");
- break;
- }
- if (sorting == ESongSorting.TR_CONFIG_ARTIST_LETTER || sorting == ESongSorting.TR_CONFIG_TITLE_LETTER)
- _CreateCategoriesLetter();
- else
- {
- if (sorting == ESongSorting.TR_CONFIG_DECADE)
- {
foreach (CSongPointer songPointer in CSongs.Sorter.SortedSongs)
{
string year = songPointer.SortString;
@@ -156,11 +108,59 @@ namespace Vocaluxe.Base
songPointer.SortString = year + "0 - " + year + "9";
}
}
- }
- _CreateCategoriesNormal(noCategoryName);
+ break;
+ case ESongSorting.TR_CONFIG_TITLE_LETTER:
+ case ESongSorting.TR_CONFIG_ARTIST_LETTER:
+ foreach (CSongPointer songPointer in CSongs.Sorter.SortedSongs)
+ songPointer.SortString = (songPointer.SortString.Length == 0 || !Char.IsLetter(songPointer.SortString, 0)) ? "#" : songPointer.SortString[0].ToString();
+ break;
+ case ESongSorting.TR_CONFIG_DATEADDED:
+ foreach (CSongPointer songPointer in CSongs.Sorter.SortedSongs)
+ songPointer.SortString = CSongs.GetSong(songPointer.SongID).DateAdded.ToString("dd/MM/yyyy");
+ break;
}
}
+ private static string _GetNoCategoryName()
+ {
+ string noCategoryName;
+ switch (CSongs.Sorter.SongSorting)
+ {
+ case ESongSorting.TR_CONFIG_NONE:
+ noCategoryName = CLanguage.Translate("TR_SCREENSONG_ALLSONGS");
+ break;
+ case ESongSorting.TR_CONFIG_FOLDER:
+ case ESongSorting.TR_CONFIG_ARTIST:
+ case ESongSorting.TR_CONFIG_ARTIST_LETTER:
+ case ESongSorting.TR_CONFIG_TITLE_LETTER:
+ noCategoryName = "";
+ Debug.Assert(false, "Should not have an uncategorized song");
+ break;
+ case ESongSorting.TR_CONFIG_EDITION:
+ noCategoryName = CLanguage.Translate("TR_SCREENSONG_NOEDITION");
+ break;
+ case ESongSorting.TR_CONFIG_GENRE:
+ noCategoryName = CLanguage.Translate("TR_SCREENSONG_NOGENRE");
+ break;
+ case ESongSorting.TR_CONFIG_LANGUAGE:
+ noCategoryName = CLanguage.Translate("TR_SCREENSONG_NOLANGUAGE");
+ break;
+ case ESongSorting.TR_CONFIG_DECADE:
+ case ESongSorting.TR_CONFIG_YEAR:
+ noCategoryName = CLanguage.Translate("TR_SCREENSONG_NOYEAR");
+ break;
+ case ESongSorting.TR_CONFIG_DATEADDED:
+ noCategoryName = "";
+ Debug.Assert(false, "Should not have an uncategorized song");
+ break;
+ default:
+ noCategoryName = "";
+ Debug.Assert(false, "Forgot category option");
+ break;
+ }
+ return noCategoryName;
+ }
+
private void _FillCategories()
{
if (!_Changed)
diff --git a/Vocaluxe/Base/CSongSorter.cs b/Vocaluxe/Base/CSongSorter.cs
index eefb796f..f1703224 100644
--- a/Vocaluxe/Base/CSongSorter.cs
+++ b/Vocaluxe/Base/CSongSorter.cs
@@ -17,7 +17,8 @@
using System;
using System.Collections.Generic;
-using System.Reflection;
+using System.Diagnostics;
+using System.Linq;
using VocaluxeLib;
using VocaluxeLib.Songs;
@@ -110,83 +111,65 @@ namespace Vocaluxe.Base
return res;
}
- private List _CreateSortList(string fieldName)
+ private void _AddSongToList(CSong song, List list)
{
- var sortList = new List();
- if (fieldName == "")
- CSongs.Filter.FilteredSongs.ForEach(song => sortList.Add(new CSongPointer(song.ID, "")));
+ string value = null;
+ List values = null;
+ switch (_SongSorting)
+ {
+ case ESongSorting.TR_CONFIG_NONE:
+ value = "";
+ break;
+ case ESongSorting.TR_CONFIG_FOLDER:
+ value = song.FolderName;
+ break;
+ case ESongSorting.TR_CONFIG_ARTIST:
+ case ESongSorting.TR_CONFIG_ARTIST_LETTER:
+ value = _IgnoreArticles == EOffOn.TR_CONFIG_ON ? song.ArtistSorting : song.Artist;
+ break;
+ case ESongSorting.TR_CONFIG_TITLE_LETTER:
+ value = _IgnoreArticles == EOffOn.TR_CONFIG_ON ? song.TitleSorting : song.Title;
+ break;
+ case ESongSorting.TR_CONFIG_EDITION:
+ values = song.Editions;
+ break;
+ case ESongSorting.TR_CONFIG_GENRE:
+ values = song.Genres;
+ break;
+ case ESongSorting.TR_CONFIG_LANGUAGE:
+ values = song.Languages;
+ break;
+ case ESongSorting.TR_CONFIG_DECADE:
+ case ESongSorting.TR_CONFIG_YEAR:
+ value = song.Year;
+ break;
+ case ESongSorting.TR_CONFIG_DATEADDED:
+ value = song.DateAdded.ToString("yyyyMMdd");
+ break;
+ default:
+ Debug.Assert(false, "Forgot sorting option");
+ break;
+ }
+ Debug.Assert(value != null || values != null, "Sorting implementation faulty");
+ if (value != null)
+ list.Add(new CSongPointer(song.ID, value));
else
{
- FieldInfo field = typeof(CSong).GetField(fieldName, BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public);
- if (field == null)
- {
- CLog.LogError("Unknow sorting field: " + fieldName);
- return _CreateSortList("");
- }
- bool isString = field.FieldType == typeof(string);
- if (!isString && field.FieldType != typeof(List))
- throw new Exception("Unkown sort field type");
- foreach (CSong song in CSongs.Filter.FilteredSongs)
- {
- object value = field.GetValue(song);
- if (isString)
- sortList.Add(new CSongPointer(song.ID, (String)value));
- else
- {
- var values = (List)value;
- if (values.Count == 0)
- sortList.Add(new CSongPointer(song.ID, ""));
- else
- {
- // ReSharper disable LoopCanBeConvertedToQuery
- foreach (String sortString in values)
- // ReSharper restore LoopCanBeConvertedToQuery
- sortList.Add(new CSongPointer(song.ID, sortString));
- }
- }
- }
+ if (list.Count == 0)
+ list.Add(new CSongPointer(song.ID, ""));
+ else
+ list.AddRange(values.Select(val => new CSongPointer(song.ID, val)));
}
- return sortList;
}
private void _SortSongs()
{
if (!_Changed)
return;
- String fieldName;
- switch (_SongSorting)
- {
- case ESongSorting.TR_CONFIG_EDITION:
- fieldName = "Editions";
- break;
- case ESongSorting.TR_CONFIG_GENRE:
- fieldName = "Genres";
- break;
- case ESongSorting.TR_CONFIG_FOLDER:
- fieldName = "FolderName";
- break;
- case ESongSorting.TR_CONFIG_ARTIST_LETTER:
- case ESongSorting.TR_CONFIG_ARTIST:
- fieldName = _IgnoreArticles == EOffOn.TR_CONFIG_ON ? "ArtistSorting" : "Artist";
- break;
- case ESongSorting.TR_CONFIG_TITLE_LETTER:
- fieldName = _IgnoreArticles == EOffOn.TR_CONFIG_ON ? "TitleSorting" : "Title";
- break;
- case ESongSorting.TR_CONFIG_YEAR:
- case ESongSorting.TR_CONFIG_DECADE:
- fieldName = "Year";
- break;
- case ESongSorting.TR_CONFIG_LANGUAGE:
- fieldName = "Languages";
- break;
- case ESongSorting.TR_CONFIG_DATEADDED:
- fieldName = "DateAdded";
- break;
- default:
- fieldName = "";
- break;
- }
- List sortList = _CreateSortList(fieldName);
+
+ List sortList = new List();
+ foreach (CSong song in CSongs.Filter.FilteredSongs)
+ _AddSongToList(song, sortList);
switch (_SongSorting)
{
case ESongSorting.TR_CONFIG_ARTIST_LETTER:
diff --git a/Vocaluxe/Base/CSongs.cs b/Vocaluxe/Base/CSongs.cs
index 14b2100e..36d0d6f2 100644
--- a/Vocaluxe/Base/CSongs.cs
+++ b/Vocaluxe/Base/CSongs.cs
@@ -332,21 +332,21 @@ namespace Vocaluxe.Base
public static void LoadSongs()
{
- CLog.StartBenchmark(1, "Load Songs");
+ CLog.StartBenchmark("Load Songs");
SongsLoaded = false;
_Songs.Clear();
- CLog.StartBenchmark(2, "List Songs");
+ CLog.StartBenchmark("List Songs");
var files = new List();
- foreach (string p in CConfig.SongFolder)
+ foreach (string p in CConfig.SongFolders)
{
string path = p;
files.AddRange(CHelper.ListFiles(path, "*.txt", true, true));
files.AddRange(CHelper.ListFiles(path, "*.txd", true, true));
}
- CLog.StopBenchmark(2, "List Songs");
+ CLog.StopBenchmark("List Songs");
- CLog.StartBenchmark(2, "Read TXTs");
+ CLog.StartBenchmark("Read TXTs");
foreach (string file in files)
{
CSong song = CSong.LoadSong(file);
@@ -356,25 +356,24 @@ namespace Vocaluxe.Base
if (song.LoadNotes())
_Songs.Add(song);
}
- CLog.StopBenchmark(2, "Read TXTs");
+ CLog.StopBenchmark("Read TXTs");
- CLog.StartBenchmark(2, "Sort Songs");
+ CLog.StartBenchmark("Sort Songs");
Sorter.SongSorting = CConfig.SongSorting;
Sorter.IgnoreArticles = CConfig.IgnoreArticles;
Categorizer.Tabs = CConfig.Tabs;
Categorizer.ObjectChanged += _HandleCategoriesChanged;
- CLog.StopBenchmark(2, "Sort Songs");
+ CLog.StopBenchmark("Sort Songs");
Category = -1;
SongsLoaded = true;
if (CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART)
{
- CLog.StartBenchmark(2, "Load Covers/Notes");
+ CLog.StartBenchmark("Load Covers/Notes");
_LoadCover();
- CLog.StopBenchmark(2, "Load Covers/Notes");
+ CLog.StopBenchmark("Load Covers/Notes");
}
- CLog.StopBenchmark(1, "Load Songs ");
- GC.Collect();
+ CLog.StopBenchmark("Load Songs ");
}
public static void LoadCover()
@@ -419,7 +418,6 @@ namespace Vocaluxe.Base
song.LoadSmallCover();
NumSongsWithCoverLoaded++;
}
- GC.Collect();
_CoverLoaded = true;
CDataBase.CommitCovers();
}
diff --git a/Vocaluxe/Base/CSound.cs b/Vocaluxe/Base/CSound.cs
index d6b55cbe..a09ba20a 100644
--- a/Vocaluxe/Base/CSound.cs
+++ b/Vocaluxe/Base/CSound.cs
@@ -16,9 +16,12 @@
#endregion
using System;
-using System.Collections.ObjectModel;
using System.IO;
-using Vocaluxe.Lib.Sound;
+using Vocaluxe.Lib.Sound.Playback;
+using Vocaluxe.Lib.Sound.Playback.Gstreamer;
+using Vocaluxe.Lib.Sound.Playback.GstreamerSharp;
+using Vocaluxe.Lib.Sound.Playback.OpenAL;
+using Vocaluxe.Lib.Sound.Playback.PortAudio;
using VocaluxeLib;
namespace Vocaluxe.Base
@@ -35,6 +38,8 @@ namespace Vocaluxe.Base
public static bool Init()
{
+ if (_Playback != null)
+ return false;
switch (CConfig.PlayBackLib)
{
case EPlaybackLib.PortAudio:
@@ -72,7 +77,14 @@ namespace Vocaluxe.Base
public static void CloseAllStreams()
{
- _Playback.CloseAll();
+ if (_Playback != null)
+ _Playback.CloseAll();
+ }
+
+ public static void Close()
+ {
+ CloseAllStreams();
+ _Playback = null;
}
#region Stream Handling
@@ -203,111 +215,5 @@ namespace Vocaluxe.Base
return stream;
}
#endregion Sounds
-
- #region Record
- private static IRecord _Record;
-
- public static void RecordInit()
- {
- switch (CConfig.RecordLib)
- {
-#if WIN
- case ERecordLib.DirectSound:
- _Record = new CDirectSoundRecord();
- break;
-#endif
-
- // case ERecordLib.PortAudio:
- default:
- _Record = new CPortAudioRecord();
- break;
- }
- }
-
- public static void RecordCloseAll()
- {
- _Record.CloseAll();
- }
-
- public static bool RecordStart()
- {
- return _Record.Start();
- }
-
- public static bool RecordStop()
- {
- return _Record.Stop();
- }
-
- public static void AnalyzeBuffer(int player)
- {
- _Record.AnalyzeBuffer(player);
- }
-
- public static int RecordGetToneAbs(int player)
- {
- return _Record.GetToneAbs(player);
- }
-
- public static int RecordGetTone(int player)
- {
- return _Record.GetTone(player);
- }
-
- public static void RecordSetTone(int player, int tone)
- {
- _Record.SetTone(player, tone);
- }
-
- public static bool RecordToneValid(int player)
- {
- return _Record.ToneValid(player);
- }
-
- public static float RecordGetMaxVolume(int player)
- {
- return _Record.GetMaxVolume(player);
- }
-
- public static int NumHalfTones(int player)
- {
- return _Record.NumHalfTones(player);
- }
-
- public static float[] ToneWeigth(int player)
- {
- return _Record.ToneWeigth(player);
- }
-
- public static ReadOnlyCollection RecordGetDevices()
- {
- ReadOnlyCollection devices = _Record.RecordDevices();
-
- if (devices != null)
- {
- foreach (CRecordDevice device in devices)
- {
- device.PlayerChannel1 = _GetPlayerFromMicConfig(device.Name, device.Driver, 1);
- device.PlayerChannel2 = _GetPlayerFromMicConfig(device.Name, device.Driver, 2);
- }
- return devices;
- }
-
- return null;
- }
-
- private static int _GetPlayerFromMicConfig(string device, string devicedriver, int channel)
- {
- for (int p = 0; p < CSettings.MaxNumPlayer; p++)
- {
- if (CConfig.MicConfig[p].Channel != 0 &&
- CConfig.MicConfig[p].DeviceName == device &&
- CConfig.MicConfig[p].DeviceDriver == devicedriver &&
- CConfig.MicConfig[p].Channel == channel)
- return p + 1;
- }
- return 0;
- }
- #endregion Record
}
}
\ No newline at end of file
diff --git a/Vocaluxe/Base/CTheme.cs b/Vocaluxe/Base/CTheme.cs
index 35180bcb..4f9dd431 100644
--- a/Vocaluxe/Base/CTheme.cs
+++ b/Vocaluxe/Base/CTheme.cs
@@ -142,22 +142,30 @@ namespace Vocaluxe.Base
#endregion Vars
#region Theme and Skin loading and writing
- public static void InitTheme()
+ public static bool Init()
{
_ListThemes();
ListSkins();
- LoadSkins();
- LoadTheme();
+ return LoadSkins() && LoadTheme();
}
- public static void LoadSkins()
+ public static bool LoadSkins()
{
+ //Fail if loading of any skin failed or no skin was loaded
+ //TODO: implement handlers that failing skins are logged and ignored
+ bool result = false;
for (int index = 0; index < _Skins.Count; index++)
{
if (_Skins[index].PartyModeID == -1)
- LoadSkin(index);
+ {
+ if (LoadSkin(index))
+ result = true;
+ else
+ return false;
+ }
}
+ return result;
}
public static bool LoadSkin(int skinIndex)
@@ -225,13 +233,14 @@ namespace Vocaluxe.Base
}
}
- public static void LoadTheme()
+ public static bool LoadTheme()
{
for (int i = 0; i < _Themes.Count; i++)
{
if (_Themes[i].Name == CConfig.Theme && _Themes[i].PartyModeID == -1)
- LoadTheme(i);
+ return LoadTheme(i);
}
+ return false;
}
public static bool LoadTheme(int themeIndex)
diff --git a/Vocaluxe/Base/CVideo.cs b/Vocaluxe/Base/CVideo.cs
index 76a7ce5e..3dee6082 100644
--- a/Vocaluxe/Base/CVideo.cs
+++ b/Vocaluxe/Base/CVideo.cs
@@ -29,8 +29,10 @@ namespace Vocaluxe.Base
private static IVideoDecoder _VideoDecoder;
#region Init
- public static void Init()
+ public static bool Init()
{
+ if (_VideoDecoder != null)
+ return false;
switch (CConfig.VideoDecoder)
{
case EVideoDecoder.FFmpeg:
@@ -44,14 +46,18 @@ namespace Vocaluxe.Base
break;
}
- _VideoDecoder.Init();
+ return _VideoDecoder.Init();
}
#endregion Init
#region Interface
- public static void CloseAll()
+ public static void Close()
{
- _VideoDecoder.CloseAll();
+ if (_VideoDecoder != null)
+ {
+ _VideoDecoder.CloseAll();
+ _VideoDecoder = null;
+ }
}
public static int GetNumStreams()
diff --git a/Vocaluxe/Base/CWebcam.cs b/Vocaluxe/Base/CWebcam.cs
index dac871aa..0b7dcb46 100644
--- a/Vocaluxe/Base/CWebcam.cs
+++ b/Vocaluxe/Base/CWebcam.cs
@@ -26,8 +26,10 @@ namespace Vocaluxe.Base
{
private static IWebcam _Webcam;
- public static void Init()
+ public static bool Init()
{
+ if (_Webcam != null)
+ return false;
switch (CConfig.WebcamLib)
{
case EWebcamLib.AForgeNet:
@@ -38,11 +40,13 @@ namespace Vocaluxe.Base
_Webcam = new CAForgeNet();
break;
}
- _Webcam.Init();
+ if (!_Webcam.Init())
+ return false;
_Webcam.Select(CConfig.WebcamConfig);
CConfig.WebcamConfig = _Webcam.GetConfig();
CConfig.SaveConfig();
+ return true;
}
public static bool GetFrame(ref CTexture tex)
@@ -57,7 +61,11 @@ namespace Vocaluxe.Base
public static void Close()
{
- _Webcam.Close();
+ if (_Webcam != null)
+ {
+ _Webcam.Close();
+ _Webcam = null;
+ }
}
public static void Pause()
diff --git a/Vocaluxe/Base/Fonts/CFonts.cs b/Vocaluxe/Base/Fonts/CFonts.cs
index 8b561072..1c904e98 100644
--- a/Vocaluxe/Base/Fonts/CFonts.cs
+++ b/Vocaluxe/Base/Fonts/CFonts.cs
@@ -361,9 +361,9 @@ namespace Vocaluxe.Base.Fonts
public static void LoadThemeFonts(string themeName, string fontFolder, CXMLReader xmlReader)
{
_LoadFontFiles(xmlReader, fontFolder, themeName);
- CLog.StartBenchmark(1, "BuildGlyphs");
+ CLog.StartBenchmark("BuildGlyphs");
_BuildGlyphs();
- CLog.StopBenchmark(1, "BuildGlyphs");
+ CLog.StopBenchmark("BuildGlyphs");
}
///
@@ -372,9 +372,9 @@ namespace Vocaluxe.Base.Fonts
public static void LoadPartyModeFonts(int partyModeID, string fontFolder, CXMLReader xmlReader)
{
_LoadFontFiles(xmlReader, fontFolder, "", partyModeID);
- CLog.StartBenchmark(1, "BuildGlyphs");
+ CLog.StartBenchmark("BuildGlyphs");
_BuildGlyphs();
- CLog.StopBenchmark(1, "BuildGlyphs");
+ CLog.StopBenchmark("BuildGlyphs");
}
public static void SaveThemeFonts(string themeName, XmlWriter writer)
diff --git a/Vocaluxe/Base/Fonts/CGlyph.cs b/Vocaluxe/Base/Fonts/CGlyph.cs
index cab5d9b6..c694c84d 100644
--- a/Vocaluxe/Base/Fonts/CGlyph.cs
+++ b/Vocaluxe/Base/Fonts/CGlyph.cs
@@ -15,6 +15,9 @@
// along with Vocaluxe. If not, see .
#endregion
+//Uncomment to make the font write the glyphs to file
+//#define FONT_DEBUG_OUTPUT
+
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
@@ -119,19 +122,15 @@ namespace Vocaluxe.Base.Fonts
_DrawBounding.Y *= _Texture.Width / _DrawBounding.Width;
_DrawBounding.Width = _Texture.Width;
_DrawBounding.Height = _Texture.Height;*/
-#pragma warning disable 162
- // ReSharper disable HeuristicUnreachableCode
- // ReSharper disable ConditionIsAlwaysTrueOrFalse
- if (false && Char.IsLetterOrDigit(chr))
+#if FONT_DEBUG_OUTPUT
+ if (Char.IsLetterOrDigit(chr))
{
if (outline > 0)
bmpCropped.Save("font_" + chr + "o" + CFonts.Style + "2.png", ImageFormat.Png);
else
bmpCropped.Save("font_" + chr + CFonts.Style + "2.png", ImageFormat.Png);
}
- // ReSharper restore ConditionIsAlwaysTrueOrFalse
- // ReSharper restore HeuristicUnreachableCode
-#pragma warning restore 162
+#endif
}
}
}
diff --git a/Vocaluxe/Base/Server/CVocaluxeServer.cs b/Vocaluxe/Base/Server/CVocaluxeServer.cs
index 154dd1db..19f91e62 100644
--- a/Vocaluxe/Base/Server/CVocaluxeServer.cs
+++ b/Vocaluxe/Base/Server/CVocaluxeServer.cs
@@ -18,8 +18,9 @@
using System;
using System.Collections.Generic;
using System.Drawing;
-using System.Linq;
using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using ServerLib;
@@ -29,16 +30,34 @@ using VocaluxeLib;
using VocaluxeLib.Menu;
using VocaluxeLib.Profile;
using VocaluxeLib.Songs;
-using System.Security.Cryptography;
namespace Vocaluxe.Base.Server
{
static class CVocaluxeServer
{
+ private class CServerController : CControllerFramework
+ {
+ public override string GetName()
+ {
+ return "App controller";
+ }
+
+ public override void Connect() {}
+
+ public override void Disconnect() {}
+
+ public override bool IsConnected()
+ {
+ return true;
+ }
+
+ public override void SetRumble(float duration) {}
+ }
+
private static CServer _Server;
//private static CDiscover _Discover;
- public static readonly CControllerFramework Controller = new CControllerFramework();
+ public static readonly CControllerFramework Controller = new CServerController();
public static void Init()
{
@@ -69,7 +88,6 @@ namespace Vocaluxe.Base.Server
CServer.AddPlaylist = _AddPlaylist;
//_Discover = new CDiscover(CConfig.ServerPort, CCommands.BroadcastKeyword);
- Controller.Init();
}
public static void Start()
@@ -83,8 +101,12 @@ namespace Vocaluxe.Base.Server
public static void Close()
{
- _Server.Stop();
- //_Discover.Stop();
+ if (_Server != null)
+ {
+ _Server.Stop();
+ _Server = null;
+ //_Discover.Stop();
+ }
}
public static string GetServerAddress()
@@ -148,7 +170,7 @@ namespace Vocaluxe.Base.Server
else
keyChar = c;
- if ((keyChar >= 0x30 && keyChar <= 0x39) || (keyChar >= 0x41 && keyChar <= 0x5A))
+ if ((keyChar >= '0' && keyChar <= '9') || (keyChar >= 'A' && keyChar <= 'Z'))
{
Keys keys = (Keys)keyChar;
if (shift)
@@ -185,7 +207,6 @@ namespace Vocaluxe.Base.Server
ID = existingProfile.ID,
FileName = existingProfile.FileName,
Active = existingProfile.Active,
- AvatarFileName = existingProfile.AvatarFileName,
Avatar = existingProfile.Avatar,
Difficulty = existingProfile.Difficulty,
UserRole = existingProfile.UserRole,
@@ -295,10 +316,10 @@ namespace Vocaluxe.Base.Server
{
try
{
- string filename = _SaveImage(avatarData, "snapshot", CSettings.FolderProfiles);
+ string filename = _SaveImage(avatarData, "snapshot", CConfig.ProfileFolders[0]);
- var avatar = new CAvatar(-1);
- if (avatar.LoadFromFile(filename))
+ var avatar = CAvatar.GetAvatar(filename);
+ if (avatar!=null)
{
CProfiles.AddAvatar(avatar);
return avatar;
diff --git a/Vocaluxe/COSFunctions.cs b/Vocaluxe/COSFunctions.cs
new file mode 100644
index 00000000..472956c6
--- /dev/null
+++ b/Vocaluxe/COSFunctions.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Vocaluxe
+{
+ static class COSFunctions
+ {
+#if WIN
+ private static bool _DefaultDllDirSet;
+ private static bool _UsePath;
+ private static bool _UseSetDllDir;
+
+ private static class CWindowsFunctions
+ {
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
+ public static extern void AddDllDirectory(string lpPathName);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
+ public static extern void SetDllDirectory(string lpPathName);
+
+ [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetForegroundWindow(IntPtr hWnd);
+
+ [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetDefaultDllDirectories(int directoryFlags);
+
+ // ReSharper disable InconsistentNaming
+ public const int LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000;
+ // ReSharper restore InconsistentNaming
+ }
+#endif
+
+ public static void AddEnvironmentPath(string path)
+ {
+ string newPath = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;
+ if (newPath.Length > 0)
+ newPath += ";";
+ newPath += path;
+
+ Environment.SetEnvironmentVariable("PATH", newPath);
+ }
+
+ public static void AddLibrarySearchpath(string path)
+ {
+#if WIN
+ if (!_DefaultDllDirSet)
+ {
+ try
+ {
+ CWindowsFunctions.SetDefaultDllDirectories(CWindowsFunctions.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
+ }
+ catch (Exception)
+ {
+ _UsePath = true;
+ _UseSetDllDir = true;
+ }
+ _DefaultDllDirSet = true;
+ }
+ if (_UsePath)
+ AddEnvironmentPath(path);
+ if (!_UseSetDllDir)
+ {
+ try
+ {
+ CWindowsFunctions.AddDllDirectory(path);
+ }
+ catch (Exception)
+ {
+ _UseSetDllDir = true;
+ }
+ }
+ if (_UseSetDllDir)
+ CWindowsFunctions.SetDllDirectory(path);
+#endif
+ }
+
+ public static void SetForegroundWindow(IntPtr hWnd)
+ {
+#if WIN
+ CWindowsFunctions.SetForegroundWindow(hWnd);
+#endif
+ }
+ }
+}
\ No newline at end of file
diff --git a/Vocaluxe/CProgrammHelper.cs b/Vocaluxe/CProgrammHelper.cs
index f4425776..800b907a 100644
--- a/Vocaluxe/CProgrammHelper.cs
+++ b/Vocaluxe/CProgrammHelper.cs
@@ -17,6 +17,7 @@
using System;
using System.IO;
+using System.Reflection;
using System.Security;
using Microsoft.Win32;
using Vocaluxe.Base;
@@ -49,6 +50,16 @@ namespace Vocaluxe
return false;
}
+ private static bool _KeyExists(string key)
+ {
+ using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(key))
+ {
+ if (rk != null)
+ return true;
+ }
+ return false;
+ }
+
///
/// Checks if a given program is installed by checking the Uninstall registry key.
///
@@ -56,10 +67,11 @@ namespace Vocaluxe
///
private static bool _IsProgramInstalled(string name)
{
- const string uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
- const string uninstallKeyx64 = @"SOFTWARE\WoW6432Node\Microsoft\Windows\CurrentVersion\Uninstall";
+ const string baseKey = @"SOFTWARE\";
+ const string baseKey64 = @"SOFTWARE\WoW6432Node\";
+ const string uninstallKey = @"Microsoft\Windows\CurrentVersion\Uninstall";
name = name.ToLower();
- return _CheckUninstallKey(name, uninstallKey) || _CheckUninstallKey(name, uninstallKeyx64);
+ return _CheckUninstallKey(name, baseKey + uninstallKey) || (_KeyExists(baseKey64) && _CheckUninstallKey(name, baseKey64 + uninstallKey));
}
private static bool _SystemDllExists(string dllName)
@@ -93,6 +105,7 @@ namespace Vocaluxe
true, true);
return false;
}
+ /*
bool vc2008Installed = _IsVC2008Installed();
if (!vc2008Installed)
{
@@ -106,7 +119,21 @@ namespace Vocaluxe
true, true);
return false;
}
+ * */
return true;
}
+
+ public static void Init()
+ {
+#if ARCH_X86
+ string path = "x86";
+#endif
+#if ARCH_X64
+ string path = "x64";
+#endif
+ path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar + path;
+ COSFunctions.AddLibrarySearchpath(path);
+ COSFunctions.AddLibrarySearchpath(path + Path.DirectorySeparatorChar + "gstreamer");
+ }
}
}
\ No newline at end of file
diff --git a/Vocaluxe/GlobalSuppressions.cs b/Vocaluxe/GlobalSuppressions.cs
index da284174..8a667a11 100644
--- a/Vocaluxe/GlobalSuppressions.cs
+++ b/Vocaluxe/GlobalSuppressions.cs
@@ -38,9 +38,6 @@ using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.Reliability", "CA2000:Objekte verwerfen, bevor Bereich verloren geht", Scope = "member", Target = "Vocaluxe.Lib.Draw.CDirect3D.#CopyScreen()")
]
[assembly: SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Scope = "type", Target = "Vocaluxe.Lib.Input.WiiMote.InputReport")]
-[assembly: SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Scope = "type", Target = "PortAudioSharp.PortAudio+PaDeviceIndex")]
-[assembly: SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Scope = "type", Target = "PortAudioSharp.PortAudio+PaSampleFormat")]
-[assembly: SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Scope = "type", Target = "PortAudioSharp.PortAudio+PaStreamCallbackFlags")]
[assembly:
SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member",
Target = "Vocaluxe.Lib.Video.Gstreamer.CGstreamerVideoWrapper.#GetFrame(System.Int32,System.Single)")]
@@ -49,19 +46,4 @@ using System.Diagnostics.CodeAnalysis;
Target = "Vocaluxe.Lib.Input.CHIDAPI.#ReadTimeout(System.IntPtr,System.Byte[]&,System.Int32,System.Int32)")]
[assembly:
SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member",
- Target = "Vocaluxe.Lib.Input.CHIDAPI.#Read(System.IntPtr,System.Byte[]&,System.Int32)")]
-[assembly: SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "PortAudioSharp.PortAudio.#Pa_GetVersionText()")]
-[assembly:
- SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member",
- Target = "PortAudioSharp.PortAudio.#Pa_GetErrorText(PortAudioSharp.PortAudio+PaError)")]
-[assembly:
- SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member",
- Target = "PortAudioSharp.PortAudio.#Pa_GetHostApiInfo(System.Int32)")]
-[assembly:
- SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "PortAudioSharp.PortAudio.#Pa_GetLastHostErrorInfo()")]
-[assembly:
- SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member",
- Target = "PortAudioSharp.PortAudio.#Pa_GetDeviceInfo(System.Int32)")]
-[assembly:
- SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member",
- Target = "PortAudioSharp.PortAudio.#Pa_GetStreamInfo(System.IntPtr)")]
\ No newline at end of file
+ Target = "Vocaluxe.Lib.Input.CHIDAPI.#Read(System.IntPtr,System.Byte[]&,System.Int32)")]
\ No newline at end of file
diff --git a/Vocaluxe/Lib/Draw/CDirect3D.cs b/Vocaluxe/Lib/Draw/CDirect3D.cs
index 11b11c21..032d952b 100644
--- a/Vocaluxe/Lib/Draw/CDirect3D.cs
+++ b/Vocaluxe/Lib/Draw/CDirect3D.cs
@@ -311,7 +311,6 @@ namespace Vocaluxe.Lib.Draw
FormBorderStyle = FormBorderStyle.None;
CenterToScreen();
_Fullscreen = true;
- CConfig.FullScreen = EOffOn.TR_CONFIG_ON;
if (WindowState == FormWindowState.Maximized)
{
@@ -321,8 +320,7 @@ namespace Vocaluxe.Lib.Draw
}
else
_DoResize();
-
- CConfig.SaveConfig();
+ ;
}
///
@@ -334,9 +332,6 @@ namespace Vocaluxe.Lib.Draw
FormBorderStyle = FormBorderStyle.Sizable;
CenterToScreen();
_Fullscreen = false;
- CConfig.FullScreen = EOffOn.TR_CONFIG_OFF;
-
- CConfig.SaveConfig();
}
#endregion resize
@@ -486,10 +481,7 @@ namespace Vocaluxe.Lib.Draw
Show();
if (CConfig.FullScreen == EOffOn.TR_CONFIG_ON)
- {
- CSettings.IsFullScreen = true;
_EnterFullScreen();
- }
//Resize window if aspect ratio is incorrect
if (Math.Abs(_W / (float)_H - CSettings.GetRenderAspect()) > 0.01)
@@ -530,7 +522,7 @@ namespace Vocaluxe.Lib.Draw
}
}
//Apply fullscreen mode
- if (CSettings.IsFullScreen != _Fullscreen)
+ if ((CConfig.FullScreen == EOffOn.TR_CONFIG_ON) != _Fullscreen)
{
if (!_Fullscreen)
_EnterFullScreen();
diff --git a/Vocaluxe/Lib/Draw/CDrawWinForm.cs b/Vocaluxe/Lib/Draw/CDrawWinForm.cs
index d5309d25..c1fd96b9 100644
--- a/Vocaluxe/Lib/Draw/CDrawWinForm.cs
+++ b/Vocaluxe/Lib/Draw/CDrawWinForm.cs
@@ -127,9 +127,6 @@ namespace Vocaluxe.Lib.Draw
targetForm.Bounds = Screen.PrimaryScreen.Bounds;
targetForm.TopMost = true;
_Fullscreen = true;
-
- CConfig.FullScreen = EOffOn.TR_CONFIG_ON;
- CConfig.SaveConfig();
}
}
@@ -146,9 +143,6 @@ namespace Vocaluxe.Lib.Draw
targetForm.TopMost = _TopMost;
targetForm.Bounds = _Bounds;
_Fullscreen = false;
-
- CConfig.FullScreen = EOffOn.TR_CONFIG_OFF;
- CConfig.SaveConfig();
}
#endregion FullScreenStuff
@@ -232,10 +226,7 @@ namespace Vocaluxe.Lib.Draw
Show();
if (CConfig.FullScreen == EOffOn.TR_CONFIG_ON)
- {
- CSettings.IsFullScreen = true;
_Maximize(this);
- }
while (_Run)
{
@@ -247,7 +238,7 @@ namespace Vocaluxe.Lib.Draw
_Run = CGraphics.UpdateGameLogic(_Keys, _Mouse);
_FlipBuffer();
- if ((CSettings.IsFullScreen && !_Fullscreen) || (!CSettings.IsFullScreen && _Fullscreen))
+ if ((CConfig.FullScreen == EOffOn.TR_CONFIG_ON) != _Fullscreen)
_ToggleFullScreen();
if (CTime.IsRunning())
diff --git a/Vocaluxe/Lib/Draw/COpenGL.cs b/Vocaluxe/Lib/Draw/COpenGL.cs
index f80147d5..5b7e19ae 100644
--- a/Vocaluxe/Lib/Draw/COpenGL.cs
+++ b/Vocaluxe/Lib/Draw/COpenGL.cs
@@ -235,7 +235,6 @@ namespace Vocaluxe.Lib.Draw
private void _EnterFullScreen()
{
_Fullscreen = true;
- CConfig.FullScreen = EOffOn.TR_CONFIG_ON;
_Restore.Location = Location;
_Restore.Width = Width;
@@ -261,19 +260,14 @@ namespace Vocaluxe.Lib.Draw
}
else
_DoResize();
-
- CConfig.SaveConfig();
}
private void _LeaveFullScreen()
{
_Fullscreen = false;
- CConfig.FullScreen = EOffOn.TR_CONFIG_OFF;
FormBorderStyle = FormBorderStyle.Sizable;
DesktopBounds = new Rectangle(_Restore.Location, new Size(_Restore.Width, _Restore.Height));
-
- CConfig.SaveConfig();
}
#endregion Helpers
@@ -433,10 +427,7 @@ namespace Vocaluxe.Lib.Draw
Show();
if (CConfig.FullScreen == EOffOn.TR_CONFIG_ON)
- {
- CSettings.IsFullScreen = true;
_EnterFullScreen();
- }
while (_Run)
{
@@ -448,7 +439,7 @@ namespace Vocaluxe.Lib.Draw
_Control.SwapBuffers();
- if (CSettings.IsFullScreen != _Fullscreen)
+ if ((CConfig.FullScreen == EOffOn.TR_CONFIG_ON) != _Fullscreen)
_ToggleFullScreen();
_CheckQueue();
diff --git a/Vocaluxe/Lib/Input/CControllerFramework.cs b/Vocaluxe/Lib/Input/CControllerFramework.cs
index 265c0858..2ac282d1 100644
--- a/Vocaluxe/Lib/Input/CControllerFramework.cs
+++ b/Vocaluxe/Lib/Input/CControllerFramework.cs
@@ -15,51 +15,63 @@
// along with Vocaluxe. If not, see .
#endregion
-using System;
using System.Collections.Generic;
using VocaluxeLib;
namespace Vocaluxe.Lib.Input
{
- public class CControllerFramework : IController
+ public abstract class CControllerFramework : IController
{
- private List _KeysPool;
+ protected bool _Initialized;
+ private readonly List _KeysPool = new List();
private List _CurrentKeysPool;
- private readonly Object _KeyCopyLock = new Object();
- private List _MousePool;
+ private readonly List _MousePool = new List();
private List _CurrentMousePool;
- private readonly Object _MouseCopyLock = new Object();
- public virtual void Init()
+ public abstract string GetName();
+
+ public virtual bool Init()
{
- _KeysPool = new List();
+ if (_Initialized)
+ return false;
_CurrentKeysPool = new List();
- _MousePool = new List();
_CurrentMousePool = new List();
- }
-
- public virtual void Close() {}
-
- public virtual void Connect() {}
-
- public virtual void Disconnect() {}
-
- public virtual bool IsConnected()
- {
+ _Initialized = true;
return true;
}
+ public virtual void Close()
+ {
+ if (!_Initialized)
+ return;
+ _CurrentKeysPool = null;
+ _CurrentMousePool = null;
+ lock (_KeysPool)
+ _KeysPool.Clear();
+ lock (_MousePool)
+ _MousePool.Clear();
+ _Initialized = false;
+ }
+
+ public abstract void Connect();
+
+ public abstract void Disconnect();
+
+ public abstract bool IsConnected();
+
public virtual void Update()
{
- lock (_KeyCopyLock)
+ if (!_Initialized)
+ return;
+ lock (_KeysPool)
{
foreach (SKeyEvent e in _KeysPool)
_CurrentKeysPool.Add(e);
_KeysPool.Clear();
}
- lock (_MouseCopyLock)
+ lock (_MousePool)
{
foreach (SMouseEvent e in _MousePool)
_CurrentMousePool.Add(e);
@@ -69,6 +81,8 @@ namespace Vocaluxe.Lib.Input
public virtual bool PollKeyEvent(ref SKeyEvent keyEvent)
{
+ if (!_Initialized)
+ return false;
if (_CurrentKeysPool.Count > 0)
{
keyEvent = _CurrentKeysPool[0];
@@ -80,6 +94,8 @@ namespace Vocaluxe.Lib.Input
public virtual bool PollMouseEvent(ref SMouseEvent mouseEvent)
{
+ if (!_Initialized)
+ return false;
if (_CurrentMousePool.Count > 0)
{
mouseEvent = _CurrentMousePool[0];
@@ -89,11 +105,13 @@ namespace Vocaluxe.Lib.Input
return false;
}
- public virtual void SetRumble(float duration) {}
+ public abstract void SetRumble(float duration);
public void AddKeyEvent(SKeyEvent keyEvent)
{
- lock (_KeyCopyLock)
+ if (!_Initialized)
+ return;
+ lock (_KeysPool)
{
_KeysPool.Add(keyEvent);
}
@@ -101,6 +119,8 @@ namespace Vocaluxe.Lib.Input
public void AddMouseEvent(SMouseEvent mouseEvent)
{
+ if (!_Initialized)
+ return;
lock (_MousePool)
{
_MousePool.Add(mouseEvent);
diff --git a/Vocaluxe/Lib/Input/IController.cs b/Vocaluxe/Lib/Input/IController.cs
index 7ad6c39b..cd6bec01 100644
--- a/Vocaluxe/Lib/Input/IController.cs
+++ b/Vocaluxe/Lib/Input/IController.cs
@@ -32,7 +32,8 @@ namespace Vocaluxe.Lib.Input
interface IController
{
- void Init();
+ string GetName();
+ bool Init();
void Close();
void Connect();
void Disconnect();
diff --git a/Vocaluxe/Lib/Input/WiiMote/CWiiMote.cs b/Vocaluxe/Lib/Input/WiiMote/CWiiMote.cs
index 6aa70841..fc29b7dc 100644
--- a/Vocaluxe/Lib/Input/WiiMote/CWiiMote.cs
+++ b/Vocaluxe/Lib/Input/WiiMote/CWiiMote.cs
@@ -16,7 +16,6 @@
#endregion
using System;
-using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
@@ -25,99 +24,79 @@ using VocaluxeLib;
namespace Vocaluxe.Lib.Input.WiiMote
{
- class CWiiMote : IController
+ class CWiiMote : CControllerFramework
{
private CWiiMoteLib _WiiMote;
- private List _KeysPool;
- private List _CurrentKeysPool;
- private readonly Object _KeyCopyLock = new Object();
-
- private List _MousePool;
- private List _CurrentMousePool;
- private readonly Object _MouseCopyLock = new Object();
-
private bool[] _ButtonStates;
private Point _OldPosition;
private bool _Connected;
private Thread _HandlerThread;
+ private AutoResetEvent _EvTerminate;
private Object _Sync;
private bool _Active;
private CRumbleTimer _RumbleTimer;
private CGesture _Gesture;
- public void Init()
+ public override string GetName()
{
+ return "WiiMote";
+ }
+
+ public override bool Init()
+ {
+ if (!base.Init())
+ return false;
_Sync = new Object();
_RumbleTimer = new CRumbleTimer();
_Gesture = new CGesture();
_HandlerThread = new Thread(_MainLoop) {Name = "WiiMote", Priority = ThreadPriority.BelowNormal};
-
- _KeysPool = new List();
- _CurrentKeysPool = new List();
-
- _MousePool = new List();
- _CurrentMousePool = new List();
+ _EvTerminate = new AutoResetEvent(false);
_ButtonStates = new bool[11];
_OldPosition = new Point();
+ return true;
}
- public void Close()
+ public override void Close()
{
_Active = false;
- _WiiMote.Disconnect();
+ if (_HandlerThread != null)
+ {
+ //Join before freeing stuff
+ //This also ensures, that no other thread is created till the current one is terminated
+ _EvTerminate.Set();
+ _HandlerThread.Join();
+ _HandlerThread = null;
+ _EvTerminate.Dispose();
+ _EvTerminate = null;
+ }
+ base.Close();
}
- public void Connect()
+ public override void Connect()
{
- if (_Active)
+ if (_Active || _HandlerThread == null)
return;
_Active = true;
_HandlerThread.Start();
}
- public void Disconnect()
+ public override void Disconnect()
{
- _Active = false;
+ //TODO: Allow reconnect
+ Close();
}
- public bool IsConnected()
+ public override bool IsConnected()
{
return _Connected;
}
- public void Update()
- {
- _CopyEvents();
- }
-
- public bool PollKeyEvent(ref SKeyEvent keyEvent)
- {
- if (_CurrentKeysPool.Count > 0)
- {
- keyEvent = _CurrentKeysPool[0];
- _CurrentKeysPool.RemoveAt(0);
- return true;
- }
- return false;
- }
-
- public bool PollMouseEvent(ref SMouseEvent mouseEvent)
- {
- if (_CurrentMousePool.Count > 0)
- {
- mouseEvent = _CurrentMousePool[0];
- _CurrentMousePool.RemoveAt(0);
- return true;
- }
- return false;
- }
-
- public void SetRumble(float duration)
+ public override void SetRumble(float duration)
{
lock (_Sync)
{
@@ -137,7 +116,7 @@ namespace Vocaluxe.Lib.Input.WiiMote
if (!_WiiMote.Connected)
{
if (!_DoConnect())
- Thread.Sleep(1000);
+ _EvTerminate.WaitOne(1000);
}
else
{
@@ -243,14 +222,7 @@ namespace Vocaluxe.Lib.Input.WiiMote
if (key != Keys.None)
- {
- var pool = new SKeyEvent(ESender.WiiMote, false, false, false, false, char.MinValue, key);
-
- lock (_KeyCopyLock)
- {
- _KeysPool.Add(pool);
- }
- }
+ AddKeyEvent(new SKeyEvent(ESender.WiiMote, false, false, false, false, char.MinValue, key));
//mouse events
const float reducing = 0.15f;
@@ -270,48 +242,13 @@ namespace Vocaluxe.Lib.Input.WiiMote
if (gesture == EGesture.ScrollDown)
wheel = 1;
- var mpool = new SMouseEvent();
- bool trigger = false;
-
if (!lb && !rb && (p.X != _OldPosition.X || p.Y != _OldPosition.Y))
- {
- mpool = new SMouseEvent(ESender.WiiMote, EModifier.None, x, y, false, false, false, wheel, lbh, false, false, false);
- trigger = true;
- }
+ AddMouseEvent(new SMouseEvent(ESender.WiiMote, EModifier.None, x, y, false, false, false, wheel, lbh, false, false, false));
else if (lb || rb)
- {
- mpool = new SMouseEvent(ESender.WiiMote, EModifier.None, x, y, lb, false, rb, wheel, false, false, false, false);
- trigger = true;
- }
-
-
- if (trigger)
- {
- lock (_MouseCopyLock)
- {
- _MousePool.Add(mpool);
- }
- }
+ AddMouseEvent(new SMouseEvent(ESender.WiiMote, EModifier.None, x, y, lb, false, rb, wheel, false, false, false, false));
_OldPosition.X = p.X;
_OldPosition.Y = p.Y;
}
-
- private void _CopyEvents()
- {
- lock (_KeyCopyLock)
- {
- foreach (SKeyEvent e in _KeysPool)
- _CurrentKeysPool.Add(e);
- _KeysPool.Clear();
- }
-
- lock (_MouseCopyLock)
- {
- foreach (SMouseEvent e in _MousePool)
- _CurrentMousePool.Add(e);
- _MousePool.Clear();
- }
- }
}
}
\ No newline at end of file
diff --git a/Vocaluxe/Lib/Playlist/CPlaylistFile.cs b/Vocaluxe/Lib/Playlist/CPlaylistFile.cs
index 4ab37b0f..ef439692 100644
--- a/Vocaluxe/Lib/Playlist/CPlaylistFile.cs
+++ b/Vocaluxe/Lib/Playlist/CPlaylistFile.cs
@@ -63,14 +63,14 @@ namespace Vocaluxe.Lib.Playlist
filename = "1";
int i = 0;
- while (File.Exists(Path.Combine(CSettings.DataPath, CSettings.FolderPlaylists, filename + ".xml")))
+ while (File.Exists(Path.Combine(CSettings.DataPath, CConfig.FolderPlaylists, filename + ".xml")))
{
i++;
- if (!File.Exists(Path.Combine(CSettings.DataPath, CSettings.FolderPlaylists, filename + i + ".xml")))
+ if (!File.Exists(Path.Combine(CSettings.DataPath, CConfig.FolderPlaylists, filename + i + ".xml")))
filename += i;
}
- PlaylistFile = Path.Combine(CSettings.DataPath, CSettings.FolderPlaylists, filename + ".xml");
+ PlaylistFile = Path.Combine(CSettings.DataPath, CConfig.FolderPlaylists, filename + ".xml");
}
XmlWriter writer;
diff --git a/Vocaluxe/Lib/Sound/CBuffer.cs b/Vocaluxe/Lib/Sound/CBuffer.cs
deleted file mode 100644
index 34831ccd..00000000
--- a/Vocaluxe/Lib/Sound/CBuffer.cs
+++ /dev/null
@@ -1,209 +0,0 @@
-using System;
-using System.IO;
-
-namespace Vocaluxe.Lib.Sound
-{
- class CBuffer : IDisposable
- {
- private const double _BaseToneFreq = 65.4064;
- public const int NumHalfTones = 17;
-
- private const int _AnalysisBufLen = 4096;
- private const int _AnalysisByteBufLen = _AnalysisBufLen * 2;
-
- private readonly Int16[] _AnalysisBuffer = new Int16[_AnalysisBufLen];
- private readonly byte[] _AnalysisByteBuffer = new byte[_AnalysisByteBufLen]; //tmp buffer (stream->tmpBuffer->(Int16)AnalysisBuffer)
-
- private static readonly int[] _SamplesPerPeriodPerTone = new int[NumHalfTones]; //Precalculated table holding sample# per period for each tone
- private readonly float[] _TmpWeight = new float[NumHalfTones]; //tmp buffer for weights (gets copied to ToneWeight when checked)
-
- private double _MaxVolume;
- private bool _NewSamples;
-
- private MemoryStream _Stream = new MemoryStream(); // full buffer
-
- public CBuffer()
- {
- ToneWeigth = new float[NumHalfTones];
- for (int i = 0; i < ToneWeigth.Length; i++)
- ToneWeigth[i] = 0.99f;
- }
-
- static CBuffer()
- {
- const double halftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave)
- //Init Array to avoid costly calculations
- for (int toneIndex = 0; toneIndex < NumHalfTones; toneIndex++)
- {
- double freq = _BaseToneFreq * Math.Pow(halftoneBase, toneIndex);
- _SamplesPerPeriodPerTone[toneIndex] = (int)Math.Round(44100.0 / freq); // samples in one period
- }
- }
-
- public int ToneAbs { get; private set; }
-
- public int Tone { get; set; }
-
- public float MaxVolume
- {
- get { return (float)_MaxVolume; }
- }
-
- public bool ToneValid { get; private set; }
-
- public float[] ToneWeigth { get; private set; }
-
- public void Reset()
- {
- lock (_Stream)
- {
- _Stream.SetLength(0L);
- _NewSamples = false;
- }
- ToneValid = false;
- ToneAbs = 0;
- Tone = 0;
- }
-
- private void _Add(byte[] bytes)
- {
- _Stream.Write(bytes, 0, bytes.Length);
- }
-
- public void ProcessNewBuffer(byte[] buffer)
- {
- // apply software boost
- //BoostBuffer(Buffer, BufferSize);
-
- // voice passthrough (send data to playback-device)
- //if (assigned(fVoiceStream)) then
- //fVoiceStream.WriteData(Buffer, BufferSize);
- lock (_Stream)
- {
- _Add(buffer);
- _NewSamples = true;
- }
- }
-
- public void AnalyzeBuffer()
- {
- if (!_NewSamples)
- return;
-
- lock (_Stream)
- {
- if (_Stream.Length >= _AnalysisByteBufLen)
- {
- _Stream.Position -= _AnalysisByteBufLen;
- _Stream.Read(_AnalysisByteBuffer, 0, _AnalysisByteBufLen);
- }
- _NewSamples = false;
- }
-
- for (int i = 0; i < _AnalysisBufLen; i++)
- _AnalysisBuffer[i] = BitConverter.ToInt16(_AnalysisByteBuffer, i * 2);
-
- try
- {
- // find maximum volume
- _FindMaxVolume();
-
- if (MaxVolume >= 0.02)
- _AnalyzeByAutocorrelation();
- else
- ToneValid = false;
- }
- catch (Exception) {}
- }
-
- private void _FindMaxVolume()
- {
- short maxVolume = 0;
- for (int i = 0; i < _AnalysisBuffer.Length / 4; i++)
- {
- short volume = _AnalysisBuffer[i];
- if (volume < 0)
- {
- if (volume == Int16.MinValue)
- {
- maxVolume = Int16.MaxValue;
- break;
- }
- volume = (short)-volume;
- }
- if (volume > maxVolume)
- maxVolume = volume;
- }
- _MaxVolume = (double)maxVolume / Int16.MaxValue;
- }
-
- private void _AnalyzeByAutocorrelation()
- {
- // prepare to analyze
- double maxWeight = -1.0;
- double minWeight = 1.0;
- int maxTone = -1;
-
- // analyze halftones
- // Note: at the lowest tone (~65Hz) and a buffer-size of 4096
- // at 44.1 (or 48kHz) only 6 (or 5) samples are compared, this might be
- // too few samples -> use a bigger buffer-size
- for (int toneIndex = 0; toneIndex < NumHalfTones; toneIndex++)
- {
- double curWeight = _AnalyzeAutocorrelationTone(toneIndex);
-
- if (curWeight > maxWeight)
- {
- maxWeight = curWeight;
- maxTone = toneIndex;
- }
-
- if (curWeight < minWeight)
- minWeight = curWeight;
-
- _TmpWeight[toneIndex] = (float)curWeight;
- }
-
- if (maxWeight - minWeight > 0.01)
- {
- Array.Copy(_TmpWeight, ToneWeigth, NumHalfTones);
-
- ToneAbs = maxTone;
- Tone = maxTone % 12;
- ToneValid = true;
- }
- else
- ToneValid = false;
- }
-
- private double _AnalyzeAutocorrelationTone(int tone)
- {
- int samplesPerPeriod = _SamplesPerPeriodPerTone[tone]; // samples in one period
-
- int accumDist = 0; // accumulated distances
-
- // compare correlating samples
- int sampleIndex = 0; // index of sample to analyze
- // Start value= index of sample one period ahead
- for (int correlatingSampleIndex = sampleIndex + samplesPerPeriod; correlatingSampleIndex < _AnalysisBufLen; correlatingSampleIndex++, sampleIndex++)
- {
- // calc distance (correlation: 1-dist/IntMax) to corresponding sample in next period
- // distance (0=equal .. IntMax=totally different) between correlated samples
- int dist = Math.Abs(_AnalysisBuffer[sampleIndex] - _AnalysisBuffer[correlatingSampleIndex]);
- accumDist += dist;
- }
-
- return 1.0 - (double)accumDist / Int16.MaxValue / _AnalysisBufLen;
- }
-
- public void Dispose()
- {
- if (_Stream != null)
- {
- _Stream.Dispose();
- _Stream = null;
- }
- GC.SuppressFinalize(this);
- }
- }
-}
\ No newline at end of file
diff --git a/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs b/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs
deleted file mode 100644
index eabf0d73..00000000
--- a/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs
+++ /dev/null
@@ -1,415 +0,0 @@
-#region license
-// This file is part of Vocaluxe.
-//
-// Vocaluxe 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 3 of the License, or
-// (at your option) any later version.
-//
-// Vocaluxe 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 Vocaluxe. If not, see .
-#endregion
-
-using System.Collections.ObjectModel;
-using SlimDX.DirectSound;
-using SlimDX.Multimedia;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using Vocaluxe.Base;
-
-namespace Vocaluxe.Lib.Sound
-{
- class CDirectSoundRecord : IRecord
- {
- private bool _Initialized;
- private List _Devices;
- private List _Sources;
-
- private readonly CBuffer[] _Buffer;
-
- public CDirectSoundRecord()
- {
- _Buffer = new CBuffer[CSettings.MaxNumPlayer];
- for (int i = 0; i < _Buffer.Length; i++)
- _Buffer[i] = new CBuffer();
-
- Init();
- }
-
- public bool Init()
- {
- DeviceCollection devices = DirectSoundCapture.GetDevices();
- _Devices = new List();
- _Sources = new List();
-
- int id = 0;
- foreach (DeviceInformation dev in devices)
- {
- using (var ds = new DirectSoundCapture(dev.DriverGuid))
- {
- var device = new CRecordDevice {Driver = dev.DriverGuid.ToString(), ID = id, Name = dev.Description, Channels = ds.Capabilities.Channels};
-
- if (device.Channels > 2)
- device.Channels = 2; //more are not supported in vocaluxe
-
- _Devices.Add(device);
-
- id++;
- }
- }
-
- _Initialized = true;
-
- return true;
- }
-
- public void CloseAll()
- {
- if (_Initialized)
- {
- Stop();
- _Initialized = false;
- }
- //System.IO.File.WriteAllBytes("test0.raw", _Buffer[0].Buffer);
- }
-
- public bool Start()
- {
- if (!_Initialized)
- return false;
-
- foreach (CBuffer buffer in _Buffer)
- buffer.Reset();
-
- var active = new bool[_Devices.Count];
- var guid = new Guid[_Devices.Count];
- var channels = new short[_Devices.Count];
- for (int dev = 0; dev < _Devices.Count; dev++)
- {
- active[dev] = false;
- if (_Devices[dev].PlayerChannel1 > 0 || _Devices[dev].PlayerChannel2 > 0)
- active[dev] = true;
- guid[dev] = new Guid(_Devices[dev].Driver);
- channels[dev] = (short)_Devices[dev].Channels;
- }
-
- for (int i = 0; i < _Devices.Count; i++)
- {
- if (active[i])
- {
- var source = new CSoundCardSource(guid[i], channels[i]) {SampleRateKhz = 44.1};
- source.SampleDataReady += _OnDataReady;
- source.Start();
-
- _Sources.Add(source);
- }
- }
- return true;
- }
-
- public bool Stop()
- {
- if (!_Initialized)
- return false;
-
- foreach (CSoundCardSource source in _Sources)
- {
- source.Stop();
- source.Dispose();
- }
- _Sources.Clear();
-
- return true;
- }
-
- public void AnalyzeBuffer(int player)
- {
- if (!_Initialized)
- return;
-
- _Buffer[player].AnalyzeBuffer();
- }
-
- public int GetToneAbs(int player)
- {
- if (!_Initialized)
- return 0;
-
- return _Buffer[player].ToneAbs;
- }
-
- public int GetTone(int player)
- {
- if (!_Initialized)
- return 0;
-
- return _Buffer[player].Tone;
- }
-
- public void SetTone(int player, int tone)
- {
- if (!_Initialized)
- return;
-
- _Buffer[player].Tone = tone;
- }
-
- public float GetMaxVolume(int player)
- {
- if (!_Initialized)
- return 0f;
-
- return _Buffer[player].MaxVolume;
- }
-
- public bool ToneValid(int player)
- {
- if (!_Initialized)
- return false;
-
- return _Buffer[player].ToneValid;
- }
-
- public ReadOnlyCollection RecordDevices()
- {
- if (!_Initialized)
- return null;
-
- if (_Devices.Count == 0)
- return null;
-
- return _Devices.AsReadOnly();
- }
-
- public int NumHalfTones(int player)
- {
- if (!_Initialized)
- return 0;
-
- return CBuffer.NumHalfTones;
- }
-
- public float[] ToneWeigth(int player)
- {
- if (!_Initialized)
- return null;
-
- return _Buffer[player].ToneWeigth;
- }
-
- private void _OnDataReady(object sender, CSampleDataEventArgs e)
- {
- if (_Initialized)
- {
- var leftBuffer = new byte[e.Data.Length / 2];
- var rightBuffer = new byte[e.Data.Length / 2];
-
- //[]: Sample, L: Left channel R: Right channel
- //[LR][LR][LR][LR][LR][LR]
- //The data is interleaved and needs to be demultiplexed
- for (int i = 0; i < e.Data.Length / 2; i++)
- {
- leftBuffer[i] = e.Data[i * 2 - (i % 2)];
- rightBuffer[i] = e.Data[i * 2 - (i % 2) + 2];
- }
-
- foreach (CRecordDevice device in _Devices)
- {
- if (device.Driver == e.Guid.ToString())
- {
- if (device.PlayerChannel1 > 0)
- _Buffer[device.PlayerChannel1 - 1].ProcessNewBuffer(leftBuffer);
-
- if (device.PlayerChannel2 > 0)
- _Buffer[device.PlayerChannel2 - 1].ProcessNewBuffer(rightBuffer);
- }
- }
- }
- }
-
- private class CSampleDataEventArgs : EventArgs
- {
- public CSampleDataEventArgs(byte[] data, Guid guid)
- {
- Data = data;
- Guid = guid;
- }
-
- public byte[] Data { get; private set; }
- public Guid Guid { get; private set; }
- }
-
- private class CSoundCardSource : IDisposable
- {
- private volatile bool _Running;
- private readonly int _BufferSize;
- private CaptureBuffer _CaptureBuffer;
- private CaptureBufferDescription _BufferDescription;
- private DirectSoundCapture _CaptureDevice;
- private readonly WaveFormat _WaveFormat;
- private Thread _CaptureThread;
- private List _Notifications;
- private int _BufferPortionCount;
- private int _BufferPortionSize;
- private WaitHandle[] _WaitHandles;
- private double _SampleRate;
- private readonly Guid _Guid;
- private readonly short _Channels;
-
- public CSoundCardSource(Guid guid, short channels)
- {
- _Guid = guid;
- _Channels = channels;
- _WaveFormat = new WaveFormat();
- SampleRateKhz = 44.1;
- _BufferSize = 2048;
- }
-
- public event EventHandler SampleDataReady = delegate { };
-
- public double SampleRateKhz
- {
- get { return _SampleRate; }
-
- set
- {
- _SampleRate = value;
-
- if (_Running)
- Restart();
- }
- }
-
- public void Start()
- {
- if (_Running)
- throw new InvalidOperationException();
-
- if (_CaptureDevice == null)
- _CaptureDevice = new DirectSoundCapture(_Guid);
-
- _WaveFormat.FormatTag = WaveFormatTag.Pcm; // Change to WaveFormatTag.IeeeFloat for float
- _WaveFormat.BitsPerSample = 16; // Set this to 32 for float
- _WaveFormat.BlockAlignment = (short)(_Channels * (_WaveFormat.BitsPerSample / 8));
- _WaveFormat.Channels = _Channels;
- _WaveFormat.SamplesPerSecond = (int)(SampleRateKhz * 1000D);
- _WaveFormat.AverageBytesPerSecond =
- _WaveFormat.SamplesPerSecond *
- _WaveFormat.BlockAlignment;
-
- _BufferPortionCount = 2;
-
- _BufferDescription.BufferBytes = _BufferSize * sizeof(short) * _BufferPortionCount * _Channels;
- _BufferDescription.Format = _WaveFormat;
- _BufferDescription.WaveMapped = false;
-
- _CaptureBuffer = new CaptureBuffer(_CaptureDevice, _BufferDescription);
-
- _BufferPortionSize = _CaptureBuffer.SizeInBytes / _BufferPortionCount;
- _Notifications = new List();
-
- for (int i = 0; i < _BufferPortionCount; i++)
- {
- var notification = new NotificationPosition {Offset = _BufferPortionCount - 1 + (_BufferPortionSize * i), Event = new AutoResetEvent(false)};
- _Notifications.Add(notification);
- }
-
- _CaptureBuffer.SetNotificationPositions(_Notifications.ToArray());
- _WaitHandles = new WaitHandle[_Notifications.Count];
-
- for (int i = 0; i < _Notifications.Count; i++)
- _WaitHandles[i] = _Notifications[i].Event;
-
- _CaptureThread = new Thread(_DoCapture) {Name = "DirectSoundCapture", IsBackground = true};
-
- _Running = true;
- _CaptureThread.Start();
- }
-
- public void Stop()
- {
- _Running = false;
-
- if (_CaptureThread != null)
- {
- _CaptureThread.Join();
- _CaptureThread = null;
- }
-
- if (_CaptureBuffer != null)
- {
- _CaptureBuffer.Dispose();
- _CaptureBuffer = null;
- }
-
- if (_Notifications != null)
- {
- foreach (NotificationPosition notification in _Notifications)
- notification.Event.Close();
-
- _Notifications.Clear();
- _Notifications = null;
- }
- }
-
- public void Restart()
- {
- Stop();
- Start();
- }
-
- private void _DoCapture()
- {
- int bufferPortionSamples = _BufferPortionSize / sizeof(byte);
-
- // Buffer type must match this.waveFormat.FormatTag and this.waveFormat.BitsPerSample
- var bufferPortion = new byte[bufferPortionSamples];
-
- _CaptureBuffer.Start(true);
-
- while (_Running)
- {
- int bufferPortionIndex = WaitHandle.WaitAny(_WaitHandles);
-
- _CaptureBuffer.Read(
- bufferPortion,
- 0,
- bufferPortionSamples,
- _BufferPortionSize * Math.Abs((bufferPortionIndex - 1) % _BufferPortionCount));
-
- SampleDataReady(this, new CSampleDataEventArgs(bufferPortion, _Guid));
- }
-
- _CaptureBuffer.Stop();
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- // ReSharper disable InconsistentNaming
- protected void Dispose(bool disposing)
- // ReSharper restore InconsistentNaming
- {
- if (disposing)
- {
- Stop();
-
- if (_CaptureDevice != null)
- {
- _CaptureDevice.Dispose();
- _CaptureDevice = null;
- }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs b/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs
deleted file mode 100644
index dc856e98..00000000
--- a/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs
+++ /dev/null
@@ -1,494 +0,0 @@
-#region license
-// This file is part of Vocaluxe.
-//
-// Vocaluxe 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 3 of the License, or
-// (at your option) any later version.
-//
-// Vocaluxe 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 Vocaluxe. If not, see .
-#endregion
-
-using System;
-using System.Collections.Generic;
-using Gst;
-using GLib;
-using System.Runtime.InteropServices;
-using Vocaluxe.Base;
-using VocaluxeLib;
-using Thread = System.Threading.Thread;
-
-namespace Vocaluxe.Lib.Sound
-{
- public class CGstreamerSharpAudio : IPlayback
- {
- private readonly Dictionary _Streams = new Dictionary();
- private static int _IDCount;
-
- [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
- private static extern void SetDllDirectory(string lpPathName);
-
- public bool Init()
- {
-#if ARCH_X86
- const string path = ".\\x86\\gstreamer";
-#endif
-#if ARCH_X64
- const string path = ".\\x64\\gstreamer";
-#endif
- SetDllDirectory(path);
- Application.Init();
- Registry reg = Registry.Get();
- reg.ScanPath(path);
-
- return Application.IsInitialized;
- }
-
- public void SetGlobalVolume(float volume)
- {
- foreach (CGstreamerSharpAudioStream stream in _Streams.Values)
- stream.Volume = volume;
- }
-
- public int GetStreamCount()
- {
- return _Streams.Count;
- }
-
- public void CloseAll()
- {
- foreach (CGstreamerSharpAudioStream stream in _Streams.Values)
- stream.Close();
- }
-
- public int Load(string media)
- {
- return Load(media, false);
- }
-
- public int Load(string media, bool prescan)
- {
- var stream = new CGstreamerSharpAudioStream(media, prescan);
- _Streams[_IDCount] = stream;
- return _IDCount++;
- }
-
- public void Close(int stream)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- _Streams[stream].Close();
- }
-
- public void Play(int stream)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- _Streams[stream].Playing = true;
- }
-
- public void Play(int stream, bool loop)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- Play(stream, loop);
- }
-
- public void Pause(int stream)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- _Streams[stream].Paused = true;
- }
-
- public void Stop(int stream)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- _Streams[stream].Stop();
- }
-
- public void Fade(int stream, float targetVolume, float seconds)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- _Streams[stream].Fade(targetVolume, seconds);
- }
-
- public void FadeAndPause(int stream, float targetVolume, float seconds)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- _Streams[stream].FadeAndPause(targetVolume, seconds);
- }
-
- public void FadeAndClose(int stream, float targetVolume, float seconds)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- _Streams[stream].FadeAndClose(targetVolume, seconds);
- }
-
- public void FadeAndStop(int stream, float targetVolume, float seconds)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- _Streams[stream].FadeAndStop(targetVolume, seconds);
- }
-
- public void SetStreamVolume(int stream, float volume)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- _Streams[stream].Volume = volume;
- }
-
- public void SetStreamVolumeMax(int stream, float volume)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- _Streams[stream].MaxVolume = volume;
- }
-
- public float GetLength(int stream)
- {
- if (!_Streams.ContainsKey(stream))
- return -1;
- return _Streams[stream].Length;
- }
-
- public float GetPosition(int stream)
- {
- if (!_Streams.ContainsKey(stream))
- return -1f;
- return _Streams[stream].Position;
- }
-
- public bool IsPlaying(int stream)
- {
- if (!_Streams.ContainsKey(stream))
- return false;
- return _Streams[stream].Playing;
- }
-
- public bool IsPaused(int stream)
- {
- if (!_Streams.ContainsKey(stream))
- return false;
- return _Streams[stream].Paused;
- }
-
- public bool IsFinished(int stream)
- {
- if (!_Streams.ContainsKey(stream))
- return true;
- return _Streams[stream].Finished;
- }
-
- public void SetPosition(int stream, float position)
- {
- if (!_Streams.ContainsKey(stream))
- return;
- _Streams[stream].Position = position;
- }
-
- public void Update()
- {
- var streamsToDelete = new List();
- foreach (KeyValuePair stream in _Streams)
- {
- if (stream.Value.Closed)
- streamsToDelete.Add(stream.Key);
- stream.Value.Update();
- }
- foreach (int key in streamsToDelete)
- _Streams.Remove(key);
- }
-
- private class CGstreamerSharpAudioStream
- {
- private Element _Element;
- private bool _Loop;
- public volatile bool Closed = true;
- public volatile bool Finished;
-
- private CFading _Fading;
- private EStreamAction _AfterFadeAction;
- private float _Volume = 1f;
-
- private float _MaxVolume = 1f;
-
- private volatile float _Duration = -1f;
- private volatile float _Position;
- private volatile bool _QueryingDuration;
-
- public CGstreamerSharpAudioStream(string media, bool prescan)
- {
- Element convert = ElementFactory.Make("audioconvert", "convert");
- Element audiosink = ElementFactory.Make("directsoundsink", "audiosink");
- var audioSinkBin = new Bin("Audiosink");
-
- if (convert == null || audiosink == null)
- {
- CLog.LogError("Could not create pipeline");
- return;
- }
-
- audioSinkBin.Add(convert);
- audioSinkBin.Add(audiosink);
- convert.Link(audiosink);
- Pad pad = convert.GetStaticPad("sink");
- GhostPad ghostpad = new GhostPad("sink", pad);
-
- if (pad == null)
- {
- CLog.LogError("Could not create pads");
- return;
- }
-
- if (!ghostpad.SetActive(true))
- {
- CLog.LogError("Could not link pads");
- return;
- }
- if (!audioSinkBin.AddPad(ghostpad))
- {
- CLog.LogError("Could not add pad");
- return;
- }
-
- _Element = ElementFactory.Make("playbin", "playbin");
- if (_Element == null)
- {
- CLog.LogError("Could not create playbin");
- return;
- }
- _Element["audio-sink"] = audioSinkBin;
- _Element["flags"] = 1 << 1;
- _Element["uri"] = new Uri(media).AbsoluteUri;
- _Element.SetState(State.Paused);
-
- Closed = false; //Enable stream
-
- // Passing CLOCK_TIME_NONE here causes the pipeline to block for a long time so with
- // prescan enabled the pipeline will wait 500ms for stream to initialize and then continue
- // if it takes more than 500ms, duration queries will be performed asynchronously
- if (prescan)
- {
- Message msg = _Element.Bus.TimedPopFiltered(0xffffffffffffffff, MessageType.AsyncDone);
- if (msg.Handle != IntPtr.Zero)
- _UpdateDuration();
- }
- }
-
- private void _OnMessage(Message msg)
- {
- if (msg.Handle == IntPtr.Zero)
- return;
- switch (msg.Type)
- {
- case MessageType.Eos:
- if (_Loop)
- Position = 0;
- else
- {
- Finished = true;
- Close();
- }
- break;
- case MessageType.Error:
- GException error;
- string debug;
- msg.ParseError(out error, out debug);
- CLog.LogError("Gstreamer error: message" + error.Message + ", code" + error.Code + " ,debug information" + debug);
- break;
- case MessageType.DurationChanged:
- if (!_QueryingDuration)
- _UpdateDuration();
- break;
- }
- msg.Unref();
- }
-
- public void Close()
- {
- if (!Closed)
- {
- Closed = true;
- Finished = true;
- var t = new Thread(_TerminateStream) {Name = "GSt Terminate"};
- t.Start();
- }
- }
-
- private void _TerminateStream()
- {
- if (_Element != null)
- {
- _Element.SetState(State.Null);
- _Element.Dispose();
- _Element = null;
- }
- }
-
- public void Play(bool loop = false)
- {
- if (_Element != null)
- _Element.SetState(State.Playing);
- _Loop = loop;
- }
-
- public void Stop()
- {
- if (_Element != null)
- _Element.SetState(State.Ready);
- Position = 0;
- }
-
- public void Fade(float targetVolume, float seconds)
- {
- _Fading = new CFading(_Volume, targetVolume, seconds);
- _AfterFadeAction = EStreamAction.Nothing;
- }
-
- public void FadeAndPause(float targetVolume, float seconds)
- {
- Fade(targetVolume, seconds);
- _AfterFadeAction = EStreamAction.Pause;
- }
-
- public void FadeAndClose(float targetVolume, float seconds)
- {
- Fade(targetVolume, seconds);
- _AfterFadeAction = EStreamAction.Close;
- }
-
- public void FadeAndStop(float targetVolume, float seconds)
- {
- Fade(targetVolume, seconds);
- _AfterFadeAction = EStreamAction.Stop;
- }
-
- public float Volume
- {
- get { return _Volume * 100f; }
- set
- {
- _Volume = value / 100f;
- if (_Element != null)
- _Element["volume"] = (_Volume * _MaxVolume);
- }
- }
-
- public float MaxVolume
- {
- get { return _MaxVolume * 100f; }
- set
- {
- _MaxVolume = value / 100f;
- Volume = _Volume;
- }
- }
-
- public float Length
- {
- get
- {
- if (_Duration < 0 && !_QueryingDuration)
- {
- _QueryingDuration = true; // Set this to avoid race conditions
- var t = new Thread(_UpdateDuration) {Name = "GSt Update Duration"};
- t.Start();
- }
- return _Duration > 0 ? _Duration : -1;
- }
- }
-
- public float Position
- {
- get
- {
- long position;
- if (!_Element.QueryPosition(Format.Time, out position))
- CLog.LogError("Could not query position");
- else
- _Position = (float)(position / (double)Constants.SECOND);
- return _Position;
- }
- set
- {
- if (_Element != null)
- _Element.SeekSimple(Format.Time, SeekFlags.Accurate | SeekFlags.Flush, (long)(value * (double)Constants.SECOND));
- }
- }
-
- public bool Paused
- {
- get { return _Element == null || _Element.TargetState == State.Paused; }
- set
- {
- if (value && _Element != null)
- _Element.SetState(State.Paused);
- }
- }
-
- public bool Playing
- {
- get { return _Element != null && (_Element.TargetState == State.Playing && !Finished); }
- set
- {
- if (value && _Element != null)
- _Element.SetState(State.Playing);
- }
- }
-
- public void Update()
- {
- while (_Element != null && _Element.Bus != null && _Element.Bus.HavePending())
- _OnMessage(_Element.Bus.Pop());
-
- if (_Fading != null)
- {
- bool finished;
- Volume = _Fading.GetValue(out finished);
- if (finished)
- {
- switch (_AfterFadeAction)
- {
- case EStreamAction.Pause:
- Paused = true;
- break;
- case EStreamAction.Stop:
- Stop();
- break;
- case EStreamAction.Close:
- Close();
- break;
- }
- _Fading = null;
- }
- }
- }
-
- private void _UpdateDuration()
- {
- _QueryingDuration = true;
- long duration = -1;
- while (duration < 0 && !Closed && !Finished && _Element != null)
- {
- if (_Element.QueryDuration(Format.Time, out duration))
- {
- _Duration = duration / (float)Constants.SECOND;
- _QueryingDuration = false;
- }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/Vocaluxe/Lib/Sound/CPortAudioHandle.cs b/Vocaluxe/Lib/Sound/CPortAudioHandle.cs
new file mode 100644
index 00000000..0406055e
--- /dev/null
+++ b/Vocaluxe/Lib/Sound/CPortAudioHandle.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using PortAudioSharp;
+using Vocaluxe.Base;
+
+namespace Vocaluxe.Lib.Sound
+{
+ ///