Audiofiles are played with wrong speed - c#

I am using NAudio in a C#-Application and my problem is, that the playback speed depends on the sampling rate. I used two Wav files that contain a 1000Hz sin wave with either Fs = 44100Hz and Fs = 88200 Hz. I checked the output signal of my soundcard with an oscilloscope. It turns out that my file with Fs = 44100 is over after half the expected time, whereas the output frequency is doubled (2kHz). When using the files in other players (e.g. windows media player, audacity) everything looks fine. When debugging I looked into the waveformat of these files and everything looked fine as well. I also varied the bit resolution resulting in no difference. I am not sure if i am just missing out of something.
I use this in another program where this problem first occured. Therefore I made a small rudimentary programm to see if I already made a mistake in my bigger application, the same problem exists there aswell.
It would be really great and highly appreciated, if someone could help me.
Kind regards
Leo
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using NAudio.Wave;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
AsioOut asioOut;
AudioFileReader afr4;
AudioFileReader afr8;
AudioFileReader afr0;
MixingWaveProvider32 mwp;
int playingID = 0;
int channelID;
Boolean audioplaying = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
asioOut = new AsioOut();
afr4 = new AudioFileReader("../wavs/sin1000Hz_1.75s_16bit_44100Hz_ramp50ms.wav");
afr8 = new AudioFileReader("../wavs/sin1000Hz_1.75s_16bit_88200Hz_ramp50ms.wav");
afr0 = new AudioFileReader("../wavs/sin14607Hz_180sec_20msRamp_fs96000_24bit_mono_doppelt.wav");
mwp = new MixingWaveProvider32();
afr4.Volume = 1.0f;
afr8.Volume = 1.0f;
for (int i = 0; i < asioOut.DriverOutputChannelCount; i++) {
Console.WriteLine(i + ": " + asioOut.AsioOutputChannelName(i));
if (asioOut.AsioOutputChannelName(i).Equals("Analog 3 (1)")) {
channelID = i;
}
}
asioOut.ChannelOffset = channelID;
asioOut.Init(mwp);
asioOut.PlaybackStopped += OnPlaybackStopped;
}
//a button to play the Fs = 44100Hz File
private void button1_Click(object sender, EventArgs e)
{
if (audioplaying == false) {
mwp.AddInputStream(afr4);
afr4.Position = 0;
audioplaying = true;
playingID = 4;
asioOut.Play();
}
}
//a button to play the Fs = 88200Hz File
private void button2_Click(object sender, EventArgs e)
{
if (audioplaying == false) {
mwp.AddInputStream(afr8);
afr8.Position = 0;
audioplaying = true;
playingID = 8;
asioOut.Play();
}
}
//a button to play just another audiofile
private void button4_Click(object sender, EventArgs e)
{
if (audioplaying == false) {
mwp.AddInputStream(afr0);
afr0.Position = 0;
audioplaying = true;
playingID = 0;
asioOut.Play();
}
}
//after playback every Input gets removed again to setup for new playback
protected virtual void OnPlaybackStopped(object sender, EventArgs e) {
if (playingID == 4) {
mwp.RemoveInputStream(afr4);
} else if (playingID == 8) {
mwp.RemoveInputStream(afr8);
} else {
mwp.RemoveInputStream(afr0);
}
audioplaying = false;
}
private void button3_Click(object sender, EventArgs e)
{
asioOut.Stop();
}
}
}

You can't use MixingWaveProvider32 to mix together streams with different WaveFormat. You need to pick a single WaveFormat and pass that into the constructor. You should then only add items that have that WaveFormat although MixingWaveProvider32 isn't enforcing that when you only have one item at a time like you are doing

Related

How can I display an image embedded in my program using the value from a random number generator?

I'm trying to build a Russian Roulette style program where you click a button and it randomly selects one of 25 images to display on screen but I can't seem to figure out how to call the images using the generator.
It works fine when I select an image manually, as seen in my code below, but anything else seems to return an error.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading.Tasks;
using System.IO;
using System.Windows.Forms;
using System.Security.Cryptography;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void label_click(object sender, EventArgs e)
{
Close();
}
int mouseX = 0, mouseY = 0;
bool mouseDown;
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
private void GOBUTN_Paint(object sender, PaintEventArgs e)
{
}
//Sharing is caring: Communism goes here
private System.Windows.Forms.Timer timtim;
int rand0;
PictureBox Rooskie = new PictureBox();
Label test = new Label();
Random rando = new Random();
List<int> duplicheck = new List<int>();
private void boopthesnoot(object sender, EventArgs e)
{
dingding:
//Hell yeah, random numbers here
rand0 = rando.Next(1, 26);
/*string combowombo = string.Join(", ", duplicheck.ToArray());
test.Text = combowombo;
test.Font = new Font("Calibri", 20);
Controls.Add(test);
test.Location = new Point(0, 200);
test.Height = 1000;
test.Width = 1000;*/
if(duplicheck.Contains(rand0))
{
goto dingding;
}
else
{
GOBUTTON.Hide();
pictureBox1.Hide();
pictureBox2.Hide();
//Fuckin image code goes here my dood
Rooskie.Width = 1160;
Rooskie.Height = 620;
Bitmap image = new Bitmap(WindowsFormsApp1.Properties.Resources._1);
Rooskie.Dock = DockStyle.Fill;
Rooskie.Image = (Image)image;
Controls.Add(Rooskie);
Rooskie.SizeMode = PictureBoxSizeMode.CenterImage;
//Aww shit, it's that timer time
timtim = new System.Windows.Forms.Timer();
timtim.Tick += new EventHandler(clockfinish);
timtim.Interval = 3000;
timtim.Start();
duplicheck.Add(rand0);
if (duplicheck.Count == 25)
{
duplicheck = new List<int>();
}
}
}
private void clockfinish(object sender, EventArgs e)
{
//CEASE THE TIMER AND GIVE ME BACK MY BUTTON
Rooskie.Image = null;
timtim.Stop();
GOBUTTON.Show();
pictureBox1.Show();
pictureBox2.Show();
}
The expected result is when the user presses the button it calls up the image without having to load it from a folder.

Refreshing a chart control

This one is driving me a bit crazy. Any help gratefully received. It's a simple program to receive temperature data from an Arduino based temp sensor, and display it in a graph control on a form. The program works fine, and parses the temp data frame a treat. However..... the graph object doesn't refresh, and the whole point is to show the data over time. I thought that the chart1.DataBind command that I put in forced a refresh. I am using Visual Studio 2013 Express. Any thoughts as to what I am doing wrong very much appreciated.
// Start of program.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace serial_port_with_events_attempt_4
{
public partial class Form1 : Form
{
string RxString;
int RxRead;
int i;
int RxDec1;
int RxDec2;
int RxDec3;
float RxFloat;
float RxFloat2;
string locnString;
public Form1()
{
InitializeComponent();
}
private void buttonStart_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM8";
serialPort1.BaudRate = 9600;
serialPort1.Open();
if (serialPort1.IsOpen)
{
buttonStart.Enabled = false;
buttonStop.Enabled = true;
textBox1.ReadOnly = false;
}
}
private void buttonStop_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
buttonStart.Enabled = true;
buttonStop.Enabled = false;
textBox1.ReadOnly = true;
}
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
RxRead = serialPort1.ReadByte();
this.Invoke(new EventHandler(DisplayText));
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
}
private void DisplayText(object sender, EventArgs e)
{
if (RxRead == 126)
{
textBox1.AppendText(Environment.NewLine);
i = 0;
}
if (i< 23)
{
if (i == 7)
{
if (RxRead == 51) // 51 in this position means that the temp sensor is the one in the wooden box
{
textBox1.AppendText("Temperature in Nick's office = ");
locnString = ("Nick's office");
}
}
if (i == 17)
{
RxDec1 = RxRead - 48; // Read the tens unit
}
if (i == 18)
{
RxDec2 = RxRead - 48; // Read the units
}
if (i == 20)
{
RxDec3 = RxRead - 49; // read the decimal
}
if (i == 22)
{
RxFloat = ((RxDec1 * 10) + RxDec2);
RxFloat2 = RxDec3;
RxFloat2 = RxFloat2 / 10;
RxFloat = RxFloat + RxFloat2;
RxString = RxFloat.ToString();
if (RxFloat < 30 && RxFloat >20)
{
// Put the value in the main text box if it is not corrupt, (checking if the range is reasonable
textBox1.AppendText(RxString); // Frig about to get the reads in the right format and added together
// Add a new line into the temperature database
temperature1DataSetTableAdapters.Temp1TableAdapter temp1tableadapter = new temperature1DataSetTableAdapters.Temp1TableAdapter();
temp1tableadapter.Insert(DateTime.Now, RxFloat, locnString);
}
// Delete any old data.
temperature1DataSetTableAdapters.TempTableAdapter temp2tableadapter = new temperature1DataSetTableAdapters.TempTableAdapter();
temp2tableadapter.DeleteTempQuery();
// The above two lines work, but I need to amend to select on date TODO
chart1.DataBind();
}
}
i=i+1;
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'temperature1DataSet.Temp' table. You can move, or remove it, as needed.
this.tempTableAdapter.Fill(this.temperature1DataSet.Temp);
}
}
}
Cheers,
Nick James

How can I send Numpad Keys through my program

I'm just trying to create a program that presses Numpad 0 in the program, every few set seconds. This is what I have so far.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
int enabled = 0;
public Form1()
{
InitializeComponent();
}
private void Start_Click(object sender, EventArgs e)
{
if (enabled == 0)
{
Start.Text = "Stop";
Timer.Enabled = true;
enabled = 1;
}
else
{
Start.Text = "Start";
Timer.Enabled = false;
enabled = 0;
label2.Text = "0";
}
}
private void Timer_Tick(object sender, EventArgs e)
{
SendKeys.Send("{NumpadIns}");
label2.Text = Convert.ToString(Convert.ToInt32(label2.Text) + 1);
}
}
}
I have tried this so far
{NumpadIns}
{NumIns}
{Num0}
{INS}
Nothing seems to work, the program I'm using with it is bound to Num Zero so it has to be Num Zero and not 0 on the top row, or Insert. Thanks (Yes I have googled but for some reason this is really hard to find).
From my experience, you should you some wrappers like Input Simulator. It is easy to use and have many pre-defined enums so you do not need to pass String argument.

SoundPlayer and MemoryStream in C#

I build a sample program that select a wav file, then you can play the selected file with 2x speed Or 4x speed
the code of the previous app is :
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.IO;
namespace PlayWave
{
public partial class Form1 : Form
{
private byte[] B;
private OpenFileDialog open;
public Form1()
{
open = new OpenFileDialog();
open.Filter = "Wav Sound File (*.Wav)|*.wav";
InitializeComponent();
}
private void SelectFile_Click(object sender, EventArgs e)
{
if (!(open.ShowDialog() == DialogResult.OK))
{
return;
}
}
private void twoX_Click(object sender, EventArgs e)
{
B = File.ReadAllBytes(open.FileName);
int samplerate = BitConverter.ToInt32(B, 24) * 2;
Array.Copy(BitConverter.GetBytes(samplerate), 0, B, 24, 4);
using (System.Media.SoundPlayer SP = new System.Media.SoundPlayer(new MemoryStream(B)))
{
SP.Play();
}
}
private void fourX_Click(object sender, EventArgs e)
{
B = File.ReadAllBytes(open.FileName);
int samplerate = BitConverter.ToInt32(B, 24) * 4;
Array.Copy(BitConverter.GetBytes(samplerate), 0, B, 24, 4);
using (System.Media.SoundPlayer SP = new System.Media.SoundPlayer(new MemoryStream(B)))
{
SP.Play();
}
}
}
}
above, I changed the value of (25,26,27,28) bytes of file which represent the sample rate of wave file then save the changes and play the file using System.Media.SoundPlayer and MemoryStream .
my problem is that when I clicked on the button the plays the file in 2x speed over 3 clicks , my program stop and error message appaer ,
can any one tell me why ?

How can I implement effective Undo/Redo into my WinForms application?

I have a WinForm text editor.
I would like to be able to allow the user to undo and redo changes in the Rich Text Box, like they can in Microsoft Word.
I have spent the past week or so researching how to do this, and most results seem to be regarding graphics applications.
The standard richTextBox1.Undo(); gives disappointing results, as it undoes everything that the user has written.
Does anybody have any idea how I could implement effective undo/redo? Preferably one which undoes/redoes the action word-by-word as opposed to character-by-character.
This is a very basic idea, and I'm sure that many improvements could be made.
I would create a String Array and incrementally store the value of the RichTextBox (In the TextChanged event, under your own conditions) in the array. As you store the value, increment the value of a counter, say stackcount. When the user undoes, decrement the stackcount and set the RichTextBox.Text = array(stackcount). If they redo, then increment the value of the counter and set the value again. If they undo and then change the text, then clear all values onwards.
I am sure that many other people may have better suggestions/changes for this, so please post in comments and I will update, or edit it yourself!
Example in C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RedoUndoApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public string[] RTBRedoUndo;
public int StackCount = 0;
public int OldLength = 0;
public int ChangeToSave = 5;
public bool IsRedoUndo = false;
private void Form1_Load(object sender, EventArgs e)
{
RTBRedoUndo = new string[10000];
RTBRedoUndo[0] = "";
}
private void undo_Click(object sender, EventArgs e)
{
IsRedoUndo = true;
if (StackCount > 0 && RTBRedoUndo[StackCount - 1] != null)
{
StackCount = StackCount - 1;
richTextBox1.Text = RTBRedoUndo[StackCount];
}
}
private void redo_Click(object sender, EventArgs e)
{
IsRedoUndo = true;
if (StackCount > 0 && RTBRedoUndo[StackCount + 1] != null)
{
StackCount = StackCount + 1;
richTextBox1.Text = RTBRedoUndo[StackCount];
}
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
if (IsRedoUndo == false && richTextBox1.Text.Substring(richTextBox1.Text.Length - 1, 1) == " ")//(Math.Abs(richTextBox1.Text.Length - OldLength) >= ChangeToSave && IsRedoUndo == false)
{
StackCount = StackCount + 1;
RTBRedoUndo[StackCount] = richTextBox1.Text;
OldLength = richTextBox1.Text.Length;
}
}
private void undo_MouseUp(object sender, MouseEventArgs e)
{
IsRedoUndo = false;
}
private void redo_MouseUp(object sender, MouseEventArgs e)
{
IsRedoUndo = false;
}
}
}
One way to do this is use the TextChanged event to periodically store the contents of richtextbox.text in an array or list, as a stack. When you undo, "pop the stack" and copy the most recent version on the stack into richtextbox.text.
TextChange can determine whether a change should be saved onto the stack, whether a new word, line, or character.

Categories

Resources