C# program 2
-
12. dubna 2012 15:01
Zdravím
- vytvořte aplikaci, která bude zpracovávat zvuk nahrávaného z mikrofonu v reálném čase. Zpracování zvuku bude probíhat v časové oblasti a výsledkem bude frekvenční spektrum. Zdrojový kód pro zachytávání zvuku zvukové karty je uložen v souboru Recorder.cs, kde jsou všechny potřebné metody okomentovány. Pro správnou funkčnost této třídy musíte do do projektu zakomponovat knihovnu NAudio.dll, která je také součástí přílohy. http://msdn.microsoft.com/en-us/library/7314433t%28v=vs.80%29.aspx
- algoritmus pro zpracování zvuku je libovolny, je však doporučeno použít algoritmus rychlé fourierovy transformace FFT, který je uložený v souboru FFT.cs, zde doporučuji použít metodu RealFFT()
- výsledek vykreslete do aplikace typu WinForm (Formulářová aplikace) - Doporučuji použít Microsoft.Chart komponentu, která je určena pro vykreslování grafů. http://www.microsoft.com/downloads/cs-cz/details.aspx?familyid=130f7986-bf49-4fe5-9ca8-910ae6ea442c - v aplikaci bude vykreslen jak původní signál tak spektrum do hlavního formulářového okna
- aplikace umožní detekci prahové hodnoty signálu - pomocí UpDown uživatelského prvku
- při detekci překročení prahové hodnoty dojde k vykreslení informace o překročení v určitém čase na obrazovku
- součástí přílohy je také třída, která vytváří druhé vlákno a používá v sobě synchronizaci pomocí třídy EventWaitHandle, což usnaďňuje poměrně velkou část řešení projektu, na studentovi tedy pouze zbývá tento kód pochopit a zakomponovat správně do svého uživatelského rozhranníhttp://www.youtube.com/watch?v=fpwuqDVwcsM&feature=player_embedded
http://czshare.com/2855804/P%C5%99%C3%ADlohy.zip
Můj postup:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { AnalyzerThread analyze = new AnalyzerThread(); Recorder rec = new Recorder(); public Form1() { InitializeComponent(); //změna rozsahu osy X1 chart1.ChartAreas[0].AxisX.Minimum = 0; chart1.ChartAreas[0].AxisX.Maximum = 2000; //změna rozsahu osy Y1 chart1.ChartAreas[0].AxisY.Minimum = -1; chart1.ChartAreas[0].AxisY.Maximum = 1; //změna rozsahu osy X2 chart2.ChartAreas[0].AxisX.Minimum = 0; chart2.ChartAreas[0].AxisX.Maximum = 500; //změna rozsahu osy Y2 chart2.ChartAreas[0].AxisY.Minimum = 0; chart2.ChartAreas[0].AxisY.Maximum = 0.6; } //graf pro vykreslení zvuku v časové oblasti public void chart1_Click(LinkedList<float> samples_measured) { foreach (float sample in samples_measured) { if (chart1.Series[0].Points.Count > 1000) chart1.Series[0].Points.RemoveAt(0); chart1.Series[0].Points.AddY(sample); } } //graf pro vykreslení frekvenčního spektra private double step_WK; public void chart2_Click(double[] samples_fft) { if (chart2.InvokeRequired) { FFTSamplesProcessed new_handler = new FFTSamplesProcessed(chart2_Click); this.Invoke(new_handler, new object[] { samples_fft }); } else { chart2.Series[0].Points.Clear(); for (int i = 0; i < (samples_fft.Length / 2); i++) { chart2.Series[0].Points.AddXY((i * step_WK), samples_fft[i]); } } } //tlačítko pro uzavření aplikace bool appRunning = false; private void button1_Click(object sender, EventArgs e) { if (appRunning) rec.StopRecording(); if (analyze.IsAnalyzerRunning) analyze.Stop(); Application.Exit(); } //tlačítko pro zastavení nahrávání private void button2_Click(object sender, EventArgs e) { button2.Enabled = !button2.Enabled; button3.Enabled = true; chart1.Enabled = false; } //tlačítko pro spouštění nahrávání private void button3_Click(object sender, EventArgs e) { button3.Enabled = !button3.Enabled; button2.Enabled = true; chart1.Enabled = true; } //tlačítko pro FFT private void button4_Click(object sender, EventArgs e) { if (button4.Text == "START") { analyze.Start(); button4.Text = "STOP"; } else { analyze.Stop(); button4.Text = "START"; } } //vybrané zařízení private int mic_id = 0; private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { this.mic_id = comboBox1.SelectedIndex; } //nastavení limitu private void numericUpDown1_ValueChanged(object sender, EventArgs e) { numericUpDown1.Maximum = 100; numericUpDown1.Minimum = 0; } //zisk private void progressBar1_Click(object sender, EventArgs e) { } //napěťová špička private void label1_Click(object sender, EventArgs e) { } } }
- Upravený Tomas-P 12. dubna 2012 15:03
- Upravený Tomas-P 17. dubna 2012 18:25
- Upravený Tomas-P 17. dubna 2012 18:44
- Upravený Tomas-P 17. dubna 2012 19:50
- Upravený Tomas-P 19. dubna 2012 15:36
- Upravený Tomas-P 19. dubna 2012 15:37
- Upravený Tomas-P 20. dubna 2012 17:09
- Upravený Tomas-P 24. dubna 2012 17:52
- Upravený Tomas-P 4. května 2012 20:02
- Upravený Tomas-P 4. května 2012 20:03
- Upravený Tomas-P 6. května 2012 18:44
Všechny reakce
-
12. dubna 2012 15:25
DD,
a na co se ptáš? Zatím jsi nenapsal vůbec nic.
JCH
- Upravený ing. Jan Chaloupek 12. dubna 2012 15:25
-
4. května 2012 20:12Dobrý den, dovolil jsem si upravit kód. Předem děkuji za recenzi
-
6. května 2012 18:06
DD,
tady ti nikdo žádnou recenzi neudělá. Pokud máš nějaký konkrétní dotaz, zeptej se.
Nečekej ale, že za tebe někdo udělá školní úkol.
JCH
- Upravený ing. Jan Chaloupek 6. května 2012 18:07
-
6. května 2012 18:52Dobrý den, u FFTSamplesProcessed se mi vypsalo: The type or namespace name 'FFTSamplesProcessed' could not be found. Předem děkuji za odpověď
-
6. května 2012 21:43
DD,
a máš ho přidaný do projektu?
Když hlásí že ho nezná, nemůže ho pravděpodobně v projektu (namespace) najít.
JCH
-
7. května 2012 12:38
1. Co by se melo v tomto radku podle vas dit?
FFTSamplesProcessednew_handler = new FFTSamplesProcessed(chart2_Click);
2. Nevidim dalsi pouziti FFTSamplesProcessed
3. Mohl byste uvest reference na zdroje, ze kterych jste vychazel?
M.
-
7. května 2012 13:34
Ahoj Miloši,
je to semestrální projekt a zadání je na prvním příspěvku nahoře. Dokonce je tam video jak by program měl vypadat.
FFT je asi furierova transformace. Proč je navázána na tlačítko nemám nejmenší tušení.
Aby šla použít v projektu je potřebné namespace této transformace přidat do projektu.
JCH
- Upravený ing. Jan Chaloupek 7. května 2012 13:35
-
7. května 2012 15:00
Ahoj Honzo,
1. S Fast Fourier Transform jsem sveho casu pracoval.
2. Mne neni jasne, odkud se vzal ten radek a kde se vyuziva jeho "vystup".
3. Neni to nic spatneho, kdyz se udela "reuse code" a radeji bych se podival na original. (V semestralni praci a v diplomce se maji pouzivat odkazy, takze by to byl dobry zacatek pro nenapadnutelny postup.)
4. Myslim, ze poslanim fora neni kontrola kodu, ale reseni problemu v casti kodu.
M.
-
7. května 2012 15:14Dobrý den, nazval jsem to chart2_Click proto, protože se mi to nabízelo. Odstavec s FFTSamplesProcessed jsem převzal od druhé osoby. Budu rád za Vaše rady. Předem děkuji
-
7. května 2012 15:30
DD,
rady na co? Jediná otázka padla na "The type or namespace name 'FFTSamplesProcessed' could not be found". Na to jsi odpoveď dostal.
JCH
-
7. května 2012 16:46
A to je prave ta chybka, ze jste prebral neco, co nemate uplne pod palcem. Je opravdu lepsi napsat treba klopotnym zpusobem kod, ale byt v obraze, co dany kod dela. Nemuzeme tady opravovat neco, pokud nemame original. V kodu chybi podstatne navaznosti.
Doporucuji postupovat v blocich a overit si jednotlive funkcionality a pak kod sesit do celku.
M.
-
7. května 2012 17:55
Originál (autor Blažej Kuhajda):
using System; using System.Windows.Forms; using System.Threading; using System.Collections.Generic; using System.Linq; using System.Text; namespace projek_fft { partial class Hlavni_okno : System.Windows.Forms.Form { Recorder rec = new Recorder() ; // vytvoreni instanci trid pro: ZAZNAM , FFT AnalyzerThread analyze = new AnalyzerThread(); #region deklarace promenych - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - //_____________________________________________________________________________________________________________________ bool appRunning = false; private int mic_id = 0; private int sampleRate = 8000; private int sampleToFFT = 512; private int channels = 1; private double step_WK; private int[] sam_rate = new int[] { 8000, 16000, 32000, 44100 }; private int[] sam_to_fft = new int[] { 512, 1024, 2048 }; //_____________________________________________________________________________________________________________________ #endregion #region metoda: vykresleni_nahravani ; vykresleni_fft - - - - - - - - - - - - - - - - - - - - - - - - - - - //_____________________________________________________________________________________________________________________ public void vykresli(LinkedList<float> samples_measured) // vykreslovani merenych dat { foreach (float vzorky in samples_measured) { if (chart1.Series[0].Points.Count > 1000) // jestli je zobrazenych vice vzorku tak prvni vymaz chart1.Series[0].Points.RemoveAt(0); chart1.Series[0].Points.AddY(vzorky); // vykresleni vzorku do grafu } try { var fpb = Math.Abs(samples_measured.Max()); if ((fpb > 0) & (fpb < 1)) ; verticalProgressBar1.Value = Convert.ToInt16(fpb * 100); } catch (Exception) { MessageBox.Show("Ver.progresbar nema data"); throw; } analyze.AddSamples( samples_measured.ToArray() ); } public void zobraz_vysledek_fft(double[] samples_fft) // vykreslovani fft dat do grafu { if (chart2.InvokeRequired) { FFTSamplesProcessed new_handler = new FFTSamplesProcessed(zobraz_vysledek_fft); this.Invoke(new_handler, new object[] {samples_fft}); } else { chart2.Series[0].Points.Clear(); for (int i = 0; i < (samples_fft.Length / 2); i++) { chart2.Series[0].Points.AddXY((i * step_WK), samples_fft[i]); // vykresleni vzorku do grafu } } } //_____________________________________________________________________________________________________________________ #endregion public Hlavni_okno() { InitializeComponent(); combo_vyber.DataSource = rec.getDeviceNames(); combo_sam_rate.DataSource = sam_rate; combo_sam_rate.Enabled = false; combo_sam_to_fft.DataSource = sam_to_fft; combo_sam_to_fft.Enabled = false; this.analyze.SAMPLES_TO_PROCESS = sampleToFFT; rec.micSamplesAvailable += new MicrophoneSamplesHandler(vykresli); analyze.signalProcessed += new FFTSamplesProcessed(zobraz_vysledek_fft); verticalProgressBar1.Maximum = 100; chart1.ChartAreas[0].AxisX.Title = " vzorky [-]"; chart2.ChartAreas[0].AxisX.Title = "f[Hz]"; chart2.ChartAreas[0].AxisX.Minimum = 0; chart2.ChartAreas[0].AxisX.Maximum = (sampleRate/2); step_WK = sampleRate / sampleToFFT; chart2.ChartAreas[0].AxisX.Interval = step_WK*10; } #region udalosti tlacitek - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //_____________________________________________________________________________________________________________________ private void combo_vyber_SelectedValueChanged(object sender, EventArgs e) // VYBER MIC { label4.Text = combo_vyber.SelectedIndex.ToString(); // jen kontrolo indexu. } private void button4_Click(object sender, EventArgs e) //EXIT APP { if (appRunning) rec.StopRecording(); if (analyze.IsAnalyzerRunning) analyze.Stop(); Application.Exit(); } private void but_start_rec_Click(object sender, EventArgs e) // START/STOP MEASURE { if (but_start_rec.Text == "Start_Measure") { if (rec == null) { rec = new Recorder(); rec.micSamplesAvailable += new MicrophoneSamplesHandler(vykresli); } this.rec.StartRecording(this.mic_id, this.sampleRate, this.channels); but_start_rec.Text = "Stop_Measure"; appRunning = true; } else { if (but_start_rec.Text == "Stop_Measure") { if (analyze.IsAnalyzerRunning) analyze.Stop(); if (this.appRunning) { this.rec.StopRecording(); this.rec = null; } but_start_rec.Text = "Start_Measure"; appRunning = false; } } } private void but_comp_fft_Click(object sender, EventArgs e) // START/STOP FFT { if (but_comp_fft.Text == "START_FFT") { analyze.Start(); but_comp_fft.Text ="STOP_FFT" ; } else { analyze.Stop(); but_comp_fft.Text = "START_FFT"; } } private void combo_vyber_SelectedIndexChanged(object sender, EventArgs e) { this.mic_id = combo_vyber.SelectedIndex ; } private void but_ref_list_Click(object sender, EventArgs e) // REFRESH LIST DEVICE { combo_vyber.DataSource = rec.getDeviceNames(); } private void set_measure_Click(object sender, EventArgs e) // NASTAVENI PARAMETRU { if (set_measure.Text == "Set_Measure") { if (analyze.IsAnalyzerRunning) analyze.Stop(); if (this.appRunning) rec.StopRecording(); set_measure.Text = "Make_Change"; but_comp_fft.Text = "START_FFT"; but_start_rec.Enabled = false; but_start_rec.Text = "Start_Measure"; but_comp_fft.Enabled = false; combo_sam_rate.Enabled = true; combo_sam_to_fft.Enabled = true; } else { this.sampleRate = sam_rate[combo_sam_rate.SelectedIndex]; this.analyze.SAMPLES_TO_PROCESS = sam_to_fft[combo_sam_to_fft.SelectedIndex]; this.sampleToFFT = sam_to_fft[combo_sam_to_fft.SelectedIndex]; this.step_WK = sampleRate / sampleToFFT; chart2.ChartAreas[0].AxisX.Maximum = (sampleRate / 2); chart2.ChartAreas[0].AxisX.Interval = step_WK * 15; set_measure.Text = "Set_Measure"; but_start_rec.Enabled = true ; but_comp_fft.Enabled = true ; analyze.be_change_parameters(); combo_sam_rate.Enabled = false; combo_sam_to_fft.Enabled = false; } } private void combo_sam_rate_SelectedIndexChanged(object sender, EventArgs e) { this.sampleRate = sam_rate[combo_sam_rate.SelectedIndex]; } private void combo_sam_to_fft_SelectedIndexChanged(object sender, EventArgs e) { this.analyze.SAMPLES_TO_PROCESS = sam_to_fft[combo_sam_to_fft.SelectedIndex]; } //_____________________________________________________________________________________________________________________ #endregion } }
-
17. května 2012 15:42Dobrý den, doplnil jsem zápis using System.Threading;, ale nepomohlo to. Předem děkuji za odpověď
-
17. května 2012 16:46
Tak se na něco zeptej.
Na nic konktrétního jsi se nezeptal.
JCH
-
17. května 2012 18:10Dobrý den, jak by se dala realizovat funkčnost programu? :-) Předem děkuji za odpověď
-
18. května 2012 8:54
DD,
to mi nepřijde jako konktrétní dotaz.
Máš vůbec nějakou představu a těch knihovnách (co dělají, jak se volají, s jakými parametry a podobně)? Bez toho se nedá rozumně začít.
Musíš vymyslet funkční přenos dat ze vstupu na výstup.
Zadání vstupů a nakonec pak vizualizaci výsledků.
.
Pokud potom narazíš na kontrétní problém, můžeme ti pomoci s jeho implementací.
Nečekej, že za tebe tady budeme řešit všechny semestrální práce. Podle mě stačilo že jsem tě vedl za ručičku v té předchozí.
JCH
- Upravený ing. Jan Chaloupek 18. května 2012 8:55
- Upravený ing. Jan Chaloupek 18. května 2012 8:55
-
19. května 2012 12:17
public void vykresli_fft(double[] samples_fft) // přichází pole s oboustranným FFT spektrem, proto níže /2 (stačí pouze jednostranné spektrum) { if (chart2.InvokeRequired) // zde se ptám, jestli je graf pro FFT volán z jiného vlákna, podmínka platí, když metodu volám z jiného vlákna { FFTSamplesProcessed new_handler = new FFTSamplesProcessed(vykresli_fft); // vytvářím nový objekt stejného typu, jak je událost, že mám vypoč. FFT this.Invoke(new_handler, new object[] { samples_fft }); // zde do nového objektu dám data, které posílá druhé vlákno a současně vyvolávám tuto metodu na vlákně, kterém běží vykreslování } else { chart2.Series[0].Points.Clear(); // vymazání grafu for (int i = 0; i < (samples_fft.Length / 2); i++) { chart2.Series[0].Points.AddXY((i * step_WK), samples_fft[i]); // vykreslování po bodech } } } -
19. května 2012 15:21
DD,
proc potřebuješ rozlišovat volání z jiného vlakna?
Z toho kódu mi uniká smysl toho opakovaného volání.
JCH
-
20. května 2012 9:17

-
13. června 2012 11:59
public void vykresli(LinkedList<float> samples_measured) { foreach (float sample in samples_measured) { if (chart1.Series[0].Points.Count > 1000) // ptám se, zda-li řada vzorků neobsahuje více než 1000 vzorků, které chci zobrazit na ose X chart1.Series[0].Points.RemoveAt(0); // odstranění vzorku z řady chart1.Series[0].Points.AddY(sample); // přidávání dat do grafu } analyze.AddSamples(samples_measured.ToArray()); } -
21. června 2012 21:54
A tohle jako chtějí na vysoké škole? :D Takové blbovinky jsem dělal o prázdninách mezi druhákem a třeťákem na střední. Tenkrát ještě v Delphi na XPčkách. To ještě byly počítače pomalé (P4 @2,4GHz), takže sem graf vykresloval přes OpenGL na grafické kartě, aby to stíhalo a FFT delal pomocí knihovny pro tento účel napsané v asembleru, využívající SSE2. Vlastní napsání přes dva cykly a nejaké ty sin a cos není sice těžké, ale bylo to taky pomalé na realtime analýzu ze zvukovky. http://www.dancelights.eu/Historie.aspx
Knihovnu na FFT v assembleru sem nepsal, takže si jí můžeš stáhnout tady http://www.fftw.org/, ale jestli máš problém s referencema, bude pro tebe snažší si napsat ty cykly ;-)
Petr Barták
.Net developer
www.uzuzu.cz -
13. července 2012 11:22
Shrnutí:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace WindowsFormsApplication1 { public partial class Form1 : Form { AnalyzerThread analyze = new AnalyzerThread(); Recorder rec = new Recorder(); public Form1() { InitializeComponent(); //změna rozsahu osy X1 chart1.ChartAreas[0].AxisX.Minimum = 0; chart1.ChartAreas[0].AxisX.Maximum = 2000; //změna rozsahu osy Y1 chart1.ChartAreas[0].AxisY.Minimum = -1; chart1.ChartAreas[0].AxisY.Maximum = 1; //změna rozsahu osy X2 chart2.ChartAreas[0].AxisX.Minimum = 0; chart2.ChartAreas[0].AxisX.Maximum = 500; //změna rozsahu osy Y2 chart2.ChartAreas[0].AxisY.Minimum = 0; chart2.ChartAreas[0].AxisY.Maximum = 0.6; } //graf pro vykreslení zvuku v časové oblasti public void vykresli(LinkedList<float> samples_measured) { foreach (float sample in samples_measured) { if (chart1.Series[0].Points.Count > 1000) // ptám se, zda-li řada vzorků neobsahuje více než 1000 vzorků, které chci zobrazit na ose X chart1.Series[0].Points.RemoveAt(0); // odstranění vzorku z řady chart1.Series[0].Points.AddY(sample); // přidávání dat do grafu } analyze.AddSamples(samples_measured.ToArray()); } //graf pro vykreslení frekvenčního spektra private double step_WK; public void vykresli_fft(double[] samples_fft) // přichází pole s oboustranným FFT spektrem, proto níže /2 (stačí pouze jednostranné spektrum) { if (chart2.InvokeRequired) // zde se ptám, jestli je graf pro FFT volán z jiného vlákna, podmínka platí, když metodu volám z jiného vlákna { FFTSamplesProcessed new_handler = new FFTSamplesProcessed(vykresli_fft); // vytvářím nový objekt stejného typu, jak je událost, kde mám vypoč. FFT this.Invoke(new_handler, new object[] { samples_fft }); // zde do nového objektu dám data, které posílá druhé vlákno a současně vyvolávám tuto metodu na vlákně, na kterém běží vykreslování } else { chart2.Series[0].Points.Clear(); // vymazání grafu for (int i = 0; i < (samples_fft.Length / 2); i++) { chart2.Series[0].Points.AddXY((i * step_WK), samples_fft[i]); // vykreslování po bodech } } } //tlačítko pro uzavření aplikace bool appRunning = false; private void button1_Click(object sender, EventArgs e) { if (appRunning) rec.StopRecording(); if (analyze.IsAnalyzerRunning) analyze.Stop(); Application.Exit(); } //tlačítko pro zastavení nahrávání private void button2_Click(object sender, EventArgs e) { button2.Enabled = !button2.Enabled; button3.Enabled = true; chart1.Enabled = false; } //tlačítko pro spouštění nahrávání private void button3_Click(object sender, EventArgs e) { button3.Enabled = !button3.Enabled; button2.Enabled = true; chart1.Enabled = true; } //tlačítko pro FFT private void button4_Click(object sender, EventArgs e) { if (button4.Text == "START") { analyze.Start(); button4.Text = "STOP"; } else { analyze.Stop(); button4.Text = "START"; } } //vybrané zařízení private int mic_id = 0; private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { this.mic_id = comboBox1.SelectedIndex; } //nastavení limitu private void numericUpDown1_ValueChanged(object sender, EventArgs e) { numericUpDown1.Maximum = 100; numericUpDown1.Minimum = 0; } //zisk private void progressBar1_Click(object sender, EventArgs e) { } //napěťová špička private void label1_Click(object sender, EventArgs e) { } } }P.S.: funkčnost 0!
-
27. prosince 2012 19:56Jsem začátečník!
-
28. prosince 2012 8:59Proto chodíš do školy.
JCH
-
28. prosince 2012 14:22Jde mi jen o odladění.