windows - Hvordan kan jeg syntetisere og udføre enkle lydbølger i C #?

Indlæg af Hanne Mølgaard Plasc

Problem



Hvis du har en lisp, så prøv ikke at sige min titel.


Men ja, hvad er den nemmeste måde at generere enkel, eller Bonus for mere kompleks savetand og andre bølger.

Bedste reference


I min erfaring viser .wav-filformatet (Wikipedia-posten andre dokumenter, der giver filformatet, brug det bedste, der er den bedste). Det er ret nemt at skrive ukomprimeret PCM. [27] [28]


For ting som sinusbølger og savetænder splittede jeg opgaven i prøveudtagning og filproduktion. Så du kan have en grænseflade som:


public interface IWave
{       
    double Sample(double time);
}


hvor Sample vil blive givet en tid større end 0 (men muligvis større end 1) og skal returnere en værdi mellem -1 og 1. (Du kan bruge en delegat til dette i stedet.) Så skriv en filgenerator for at oprette en wav-fil baseret på prøvevarigheden (f.eks. '100000 bølger') og prøvefrekvens (f.eks. 50000 Hz).


Så er det bare et tilfælde at implementere IWave hensigtsmæssigt - f.eks. En version, der returnerer sin(time / (2 * pi)) for en enkel sinusbølge, eller (time \% 1.0) * 2 - 1 til en sawtooth. For bonusforlystelser kan du skrive komposition funktioner til at fremskynde eller bremse bølgen, forstærke den, kombinere andre bølger osv. Filgeneratoren behøver ikke at vide nogen af det selvfølgelig. Det ville bare være nødvendigt at tage en enkelt IWave og prøve det passende antal gange og scalere [[-1, 1]] rækkevidden til [[0, 255]] passende.

Andre referencer 1


Bare for at uddybe hvad Jon allerede sagde - alt hvad du gør er at oprette en 8-bit (dvs. byte [[1024]]) eller 16-bit buffer og udfylde den (dvs. for en firkantet bølge det er [[255 255 255 255 0 0 0 0 255 255 255 255 0 0 0 0]]).

Andre referencer 2


Se dette spørgsmål til prøvekode på hvordan man genererer en sinusbølge i C #. Udvidelse af det til firkantede eller savetænder ville være ret nemt. Du kan generere mere komplekse bølgeformer ved at blande sammen enkle.


Du kan også bruge klassen NAudio WaveFileWriter til at skrive de genererede data til en WAV-fil, hvis du har brug for. [30]

Andre referencer 3


Der er en Charles Petzold-artikel Simple Electronic Music Sequencer for Silverlight baseret på Gilles Khouzams blogindlæg. Afspilning af Wave-filer i Silverlight og Pete Browns Oprettelse af lyd ved hjælp af MediaStreamSource i Silverlight 3 Beta. Mike Hodnick har et nyttigt blogpost med prøvekode baseret på Petzold artiklen kaldet Digital Audio Synthesis på Windows Phone 7. [31] [32] [33] [34]


I XAML i hovedvinduet introducerer Mike et medieelement


<MediaElement x:Name="media"/>


og bruger derefter metoden SetSource til at indstille medieelementets kilde til den bølge, han konstruerer


this.media.SetSource(new TonesSource());
this.media.Play();


Mike's s ToneSource underklasser hans BaseSource, som igen er underklasse MediaStreamSource og tilsidesætter flere af dens metoder: OpenMediaAsync, GetSampleAsync, SeekAsync, [[CloseMedia, GetDiagnosticAsync og SwitchMediaStreamAsync. Der er mere om dem i MSDN-dokumentationen; Mike 's kode i sig selv er ikke lang, men involverer bitskift og skrivning til hukommelsesstrømme og er værd at se på i kilden, der findes i Mikes blogindlæg. [35] [36]


Mike 's ToneSource klasse giver derefter stereoprøver


protected override StereoSample GetSample()
{
    short left = 0;
    short right = 0;

    foreach (var oscillator in this.leftOscillators)
        left += oscillator.GetNextSample();

    foreach (var oscillator in this.rightOscillators)
        right += oscillator.GetNextSample();

    return new StereoSample() { Left = left, Right = right };
}


ved hjælp af hans Oscillator klasse


public short GetNextSample()
{
    ushort wholePhaseAngle = (ushort)(phaseAngle >> 16);
    short amplitude = 0;
    amplitude = (short)(short.MaxValue * Math.Sin(2 * Math.PI * wholePhaseAngle / ushort.MaxValue));
    amplitude = (short)((amplitude * multiplier) >> 16);
    phaseAngle += phaseAngleIncrement;

    return amplitude;
}


NoiseSource Mike giver også, er endnu enklere end hans ToneSource


protected override StereoSample GetSample()
{
    return new StereoSample()
    {
        Left = (short)random.Next(short.MinValue, short.MaxValue),
        Right = (short)random.Next(short.MinValue, short.MaxValue)
    };
}