Xamarin Urho IOS how to set up an application? - c#

I am following this example but it is not that useful:
https://github.com/xamarin/urho-samples/tree/master/FeatureSamples/Core/29_SoundSynthesis
anyhow I am getting an run time error that says: The application is not configured yet.
but I made an application object .
the error happen a node = new Node();
what am I missing
this is my class:
using System;
using Urho.Audio;
using Urho;
using Urho.Resources;
using Urho.Gui;
using System.Diagnostics;
using System.Globalization;
namespace Brain_Entrainment
{
public class IsochronicTones : Urho.Application
{
/// Scene node for the sound component.
Node node;
/// Sound stream that we update.
BufferedSoundStream soundStream;
public double Frequency { get; set; }
public double Beat { get; set; }
public double Amplitude { get; set; }
public float Bufferlength { get; set; }
const int numBuffers = 3;
public IsochronicTones(ApplicationOptions AppOption) : base(AppOption)
{
Amplitude = 1;
Frequency = 100;
Beat = 0;
Bufferlength = Int32.MaxValue;
}
public void play()
{
Start();
}
protected override void OnUpdate(float timeStep)
{
UpdateSound();
base.OnUpdate(timeStep);
}
protected override void Start()
{
base.Start();
CreateSound();
}
void CreateSound()
{
// Sound source needs a node so that it is considered enabled
node = new Node();
SoundSource source = node.CreateComponent();
soundStream = new BufferedSoundStream();
// Set format: 44100 Hz, sixteen bit, mono
soundStream.SetFormat(44100, true, false);
// Start playback. We don't have data in the stream yet, but the
//SoundSource will wait until there is data
// as the stream is by default in the "don't stop at end" mode
source.Play(soundStream);
}
void UpdateSound()
{
// Try to keep 1/10 seconds of sound in the buffer, to avoid both
//dropouts and unnecessary latency
float targetLength = 1.0f / 10.0f;
float requiredLength = targetLength -
Bufferlength;//soundStream.BufferLength;
float w = 0;
if (requiredLength < 0.0f)
return;
uint numSamples = (uint)(soundStream.Frequency * requiredLength);
if (numSamples == 0)
return;
// Allocate a new buffer and fill it with a simple two-oscillator
//algorithm.The sound is over - amplified
// (distorted), clamped to the 16-bit range, and finally lowpass -
//filtered according to the coefficient
var newData = new short[numSamples];
for (int i = 0; i < numSamples; ++i)
{
float newValue = 0;
if (Beat == 0)
{
newValue = (float)(Amplitude * Math.Sin(Math.PI * Frequency * i / 44100D));
}
else
{
w = (float)(1D * Math.Sin(i * Math.PI * Beat / 44100D));
if (w < 0)
{
w = 0;
}
newValue = (float)(Amplitude * Math.Sin(Math.PI * Frequency * i / 44100D));
}
//accumulator = MathHelper.Lerp(accumulator, newValue, filter);
newData[i] = (short)newValue;
}
// Queue buffer to the stream for playback
soundStream.AddData(newData, 0, newData.Length);
}
}
}

Related

C# Convolution algorithm is producing a very loud .wav file

I am trying to create a convolution reverb algorithm that takes a sound input signal and convolves it in the frequency domain with an impulse response. I have been trying to debug the code for a week and I cannot seem to find where the error is. The output of the algorithm is a .wav file that for some reason is very loud in the beginning but still sounds echoey at the end. I am using Aforge .net libraryLink to compute the FFT and the fault does not lie within the coding of that algorithm. Here is my code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using AForge.Math;
using NWaves.Operations.Convolution;
using UnityEngine;
public class ConvolutionReverbTest : MonoBehaviour {
[SerializeField] private AudioClip input;
[SerializeField] private AudioClip impulseResponse;
// ir
private float[] irData;
private Complex[] irc;
// input
private float[] inputData;
private Complex[] inputc;
// conv. reverb values
private int fftSize = 0; // F = N + M - 1 --> Also to the power of 2
// muliplication in freq domain
private Complex[] multiplication;
// output signal
private float[] output;
private void Start() {
GetAudioData();
Convolve();
}
private void Convolve() {
// calculate the fft of input data
FourierTransform.FFT(inputc, FourierTransform.Direction.Forward);
// calculate fft of impulse response
FourierTransform.FFT(irc, FourierTransform.Direction.Forward);
// multiply them in frequency domain
multiplication = new Complex[fftSize];
for (int i = 0; i < fftSize; i++) {
multiplication[i] = inputc[i] * irc[i];
multiplication[i] *= fftSize; // normalize it
}
// calculate the ifft of the multiplication
FourierTransform.FFT(multiplication, FourierTransform.Direction.Backward);
// save output signal as wave file
output = new float[fftSize];
for (int i = 0; i < fftSize; i++) {
output[i] = (float) multiplication[i].Re;
}
SaveOutputSignal(output);
}
private Complex ComplexMultiply(Complex a, Complex b) {
return new Complex(a.Re * b.Re - a.Im * b.Im, a.Re * b.Im + a.Im * b.Re);
}
private void CalculateFftSize() {
fftSize = Mathf.NextPowerOfTwo(inputData.Length + irData.Length - 1);
}
private void GetAudioData() {
// get data of ir signal
irData = new float[impulseResponse.samples];
impulseResponse.GetData(irData, 0);
// get data of input signal
inputData = new float[input.samples];
input.GetData(inputData, 0);
CalculateFftSize();
// change values accordingly of both signals --> zero padding + complex numbers
irData = ZeroPadding(irData);
irc = new Complex[irData.Length];
for (int i = 0; i < irData.Length; i++) {
irc[i].Re = irData[i];
}
inputData = ZeroPadding(inputData);
inputc = new Complex[inputData.Length];
for (int i = 0; i < inputData.Length; i++) {
inputc[i].Re = inputData[i];
}
}
private float[] ZeroPadding(float[] data) {
List<float> newData = new List<float>(data);
int N = data.Length;
for (int i = 0; i < (fftSize - N); i++) {
newData.Add(0);
}
return newData.ToArray();
}
private void SaveOutputSignal(float[] outputSignal) {
string filename = "outputSignal.txt";
// save the output signal to a txt file
File.WriteAllLines(Path.Combine(Application.streamingAssetsPath, filename),
outputSignal.Select(d => d.ToString()));
new WaveFile().SaveAudio(Path.Combine(Application.streamingAssetsPath, "output.wav"), outputSignal.Length, 1, outputSignal, input.frequency);
}
}
Here is also a picture of the output signal in audacity:
Any help is greatly appreciated.

Microphone input's maximum float number is 1. How to make it bigger and change it from 1? Unity C#

I have a code that takes a microphone input(when pressing "T)" and returns it as a float number (one final float number). However, when I yell or blow into microphone the maximum float it prints is 1 and no matter how I yell or say quietly after it printed 1, it keeps printing 1 only. How to change it to a bigger number. Let's say if I yell it would return a bigger number than if I just say quietly.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class MicInputs : MonoBehaviour
{
public enum micActivation
{
HoldToSpeak,
}
public micActivation micControl;
private float sample_max = 0.0f;
public static float MicLoudFloat;
public List<float> recorded_values = new List<float>();
private string theMicroDevice;
AudioClip recordOfClips;
//microphone initialization
void MicroInitialization()
{
if (theMicroDevice == null) theMicroDevice = Microphone.devices[0];
recordOfClips = Microphone.Start(theMicroDevice, true, 999, 44100);
}
void StopMicrophone()
{
Microphone.End(theMicroDevice);
Maximum_Level(); // Collect the final sample
MicLoudFloat = sample_max;
print(MicLoudFloat);
}
void Awake()
{
recordOfClips = AudioClip.Create("nameOfClip", 128, 2, 1000, true);
}
//AudioClip clip = myRecordedOrOwnClip;
//reate(string name, int lengthSamples, int channels, int frequency,
bool stream,
//_sampleWindow = clip.samples;
//AudioClip _clipRecord = new AudioClip();
//AudioClip _clipRecord = AudioClip.Create("nameOfClip", 128, 2, 1,
true);
int samplesWindows = 128;
//=========THIS IS THE START OF THE METHOD========
// get data from microphone into audioclip
float Maximum_Level()
{
float[] waveData = new float[samplesWindows];
int micPosition = Microphone.GetPosition(null) - (samplesWindows
+1); // null means the first microphone
if (micPosition < 0) return 0;
recordOfClips.GetData(waveData, micPosition);
// Getting a peak on the last 128 samples
for (int i = 0; i < samplesWindows; i++)
{
float wavePeak = waveData[i] * waveData[i];
if (wavePeak > sample_max)
{
sample_max = wavePeak;
}
}
return sample_max;
//float maximum_level = 0;
//float[] waveData = new float[samplesWindows];
//int micPosition = Microphone.GetPosition(null) - (samplesWindows
+ 1); // null means the first microphone
//if (micPosition < 0) return 0;
//recordOfClips.GetData(waveData, micPosition);
//// Getting a peak on the last 128 samples
//for (int i = 0; i < samplesWindows; i++)
//{
// float wavePeak = waveData[i] * waveData[i];
// if (maximum_level < wavePeak)
// {
// maximum_level = wavePeak;
// recorded_values.Add(maximum_level);
// }
//}
//float max = recorded_values.Max();
////print(max);
//return max;
//print(maximum_level);
//return maximum_level;
}
//=========THIS IS THE END OF THE METHOD========
void Update()
{
if (micControl == micActivation.HoldToSpeak)
{
//if (Microphone.IsRecording(theMicroDevice) &&
Input.GetKey(KeyCode.T) == false)
//StopMicrophone();
//
if (Input.GetKeyDown(KeyCode.T)){ //Push to talk
MicroInitialization();
}
//
if (Input.GetKeyUp(KeyCode.T)){
StopMicrophone();
}
}
Maximum_Level();
// levelMax equals to the highest normalized value power 2, a small
number because < 1
// pass the value to a static var so we can access it from anywhere
//print(MicLoudFloat);
}
//bool isItInitialized;
//// start mic when scene starts
//void OnEnable()
//{
// MicroInitialization();
// isItInitialized = true;
//}
////stop mic when loading a new level or quit application
//void OnDisable()
//{
// StopMicrophone();
//}
//void OnDestroy()
//{
// StopMicrophone();
//}
// detects if the mic gets started & stopped when application gets
focused
//void OnApplicationFocus(bool focus)
//{
// if (focus)
// {
// //Debug.Log("Focus");
// if (!isItInitialized)
// {
// //Debug.Log("Init Mic");
// MicroInitialization();
// isItInitialized = true;
// }
// }
// if (!focus)
// {
// //Debug.Log("Pause");
// StopMicrophone();
// //Debug.Log("Stop Mic");
// isItInitialized = false;
// }
//}
}
The sensor returns only a 0 or a 1, it's not 0->inf, if you want to something else, like checking how load is the voice from 0 to 100, you could record it and check the audio file highest bump and return that.

PictureBox updates only on resize

Trying to display a graph on a Form application.
Created a PictureBox control and initialized this class with its value.
On resize, graph always updates; on mouse scroll, it hardly does.
It's GraphBox , PictureBox control, inside a GraphBoxPanel, Panel control.
This the class:
public struct DLT_measure_item
{
public DateTime ts;
public float value;
public int id;
public int X;
public int Y;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct dlt_ser_meas
{
public byte msg_id; // 'D'
public byte meas_count; // Number of measures
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] port; // Module ID (4b) + Port ID (4b)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public float[] meas; // measure
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] msg_end;
}
public class manageGraph
{
private PictureBox box;
public bool displayGrid = true;
private int horAxisMin_p = 0;
private int horAxisMax_p = 300;
private float verAxisMin_p = 0;
private float verAxisMax_p = 40;
public int horAxisMin
{
get { return this.horAxisMin_p; }
set
{
if (value < horAxisMax_p)
{
this.horAxisMin_p = value;
reDraw();
}
}
}
public int horAxisMax
{
get { return this.horAxisMax_p; }
set
{
if (value > horAxisMin_p)
{
this.horAxisMax_p = value;
reDraw();
}
}
}
public float verAxisMin
{
get { return this.verAxisMin_p; }
set
{
if (value < verAxisMax_p)
{
this.verAxisMin_p = value;
verPointPerUnit = graphArea.Height / (verAxisMax_p - this.verAxisMin_p);
}
}
}
public float verAxisMax
{
get { return this.verAxisMax_p; }
set
{
if (value > verAxisMin_p)
{
this.verAxisMax_p = value;
verPointPerUnit = graphArea.Height / (this.verAxisMax_p - verAxisMin_p);
}
}
}
Pen axes = new Pen(Color.Black, (float)1.5);
public int horAxisSpacing = 30;
public int verAxisSpacing = 20;
public int horAxis = 20;
public int verAxis = 20;
private float horPointPerUnit = 1;
private float verPointPerUnit = 1;
public int horAxisTickLen = 5;
public int verAxisTickLen = 5;
public bool horAxisShowTime = false;
private Rectangle graphArea = new Rectangle();
public void reDraw()
{
box.Image.Dispose();
Bitmap GraphBlankImage = new Bitmap(box.Width, box.Height);
box.Image = GraphBlankImage;
updatePointPerUnit();
drawGrid();
box.Refresh();
}
public manageGraph(PictureBox targetImageBoxbox)
{
box = targetImageBoxbox;
horAxisMin_p = 0;
horAxisMax_p = 300;
verAxisMin_p = 0F;
verAxisMax_p = 50F;
updatePointPerUnit();
}
private Point measToPoint(DLT_measure_item measure) {
Point coords = new Point();
coords.X = graphArea.Width - (int)(
((DateTime.Now - measure.ts).TotalSeconds + horAxisMin_p) * horPointPerUnit ) ;
coords.Y = graphArea.Height - (int)(
((measure.value - verAxisMin_p) * verPointPerUnit));
return coords;
}
public manageGraph(PictureBox targetImageBoxbox,
int xmin, int xmax, float ymin, float ymax)
{
box = targetImageBoxbox;
horAxisMin_p = xmin;
horAxisMax_p = xmax;
verAxisMin_p = ymin;
verAxisMax_p = ymax;
updatePointPerUnit();
}
private void updateGraphArea()
{
graphArea = new Rectangle(0, 0, box.Width - horAxis, box.Height - verAxis);
}
private void updatePointPerUnit()
{
updateGraphArea();
horPointPerUnit = graphArea.Width / (horAxisMax_p - horAxisMin_p);
verPointPerUnit = graphArea.Height / (verAxisMax_p - verAxisMin_p);
}
public void drawGrid()
{
//updatePointPerUnit();
using (Graphics g = Graphics.FromImage(box.Image))
{
// X axis
g.DrawLine(axes, graphArea.Left, graphArea.Bottom, box.Width, graphArea.Bottom);
// Y axis
g.DrawLine(axes, graphArea.Right + 1, graphArea.Top, graphArea.Right +1, graphArea.Bottom);
using (Font ArialFont = new Font("Arial", 10))
{
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
// Put x labels
for (int i = 1; i <= (graphArea.Width / horPointPerUnit); i = i + (int)(horAxisSpacing / horPointPerUnit ) + 1)
{
g.DrawString((i).ToString(), ArialFont, Brushes.Black, graphArea.Width - ( i * horPointPerUnit) - 5, graphArea.Bottom +5);
g.DrawLine(axes, graphArea.Width - (i * horPointPerUnit), graphArea.Bottom + (horAxisTickLen / 2), graphArea.Width - (i * horPointPerUnit), graphArea.Bottom - (horAxisTickLen / 2));
}
// Put y labels
for (int i = 1; i <= (graphArea.Height / verPointPerUnit); i = i + (int)(verAxisSpacing / verPointPerUnit) +1)
{
g.DrawString((i).ToString(), ArialFont, Brushes.Black, graphArea.Right + 1 , graphArea.Height - (i * verPointPerUnit) - 8);
g.DrawLine(axes, graphArea.Width - (verAxisTickLen / 2), (i * verPointPerUnit), graphArea.Width + (verAxisTickLen / 2), (i * verPointPerUnit));
}
}
/*Put some random data*/
DLT_measure_item testmeas = new DLT_measure_item();
Point testGraphPoint = new Point();
testmeas.ts = DateTime.Now;
testmeas.value = 0;
testGraphPoint = measToPoint(testmeas);
g.FillEllipse(Brushes.Blue, testGraphPoint.X, testGraphPoint.Y, 4, 4);
for (double i = 0; i < 300; i++)
{
double x = i;
double freq = 10;
double y = 30 - (i/10);
testmeas.value = (float)y;
testmeas.ts = DateTime.Now.AddSeconds(-1 * i);
testGraphPoint = measToPoint(testmeas);
g.FillEllipse(Brushes.Red, testGraphPoint.X, testGraphPoint.Y, 2,2);
}
}
}
}
The initialization:
public DLThermalogMainForm()
{
InitializeComponent();
Bitmap GraphBlankImage = new Bitmap(GraphBox.Width, GraphBox.Height);
GraphBox.Image = GraphBlankImage;
myGraph = new manageGraph(GraphBox);
myGraph.drawGrid();
}
Those the handlers:
private void Form1_ResizeEnd(object sender, EventArgs e)
{
myGraph.reDraw();
OutputTextBox.AppendText("Resize." + Environment.NewLine);
}
private void GraphBox_MouseMove(object sender, MouseEventArgs e)
{
//Get the focus to have the wheel working
GraphBoxPanel.Focus();
}
private void GraphBoxPanel_MouseWheel(object sender, MouseEventArgs e)
{
// Change x axis max value to zoom in/out the graph
myGraph.horAxisMax += e.Delta/ 120;
myGraph.reDraw();
}
On resize event, it always redraws; on mouse wheel, it does quickly only with small horAxisMax values (does it makes sense???), but for larger, it takes many seconds to update, or doesn't at all.
Thank you very much
Change reDraw like this:
public void reDraw()
{
box.Image.Dispose();
Bitmap GraphBlankImage = new Bitmap(box.ClientSize.Width, box.ClientSize.Height);
updatePointPerUnit();
drawGrid(GraphBlankImage);
box.Image = GraphBlankImage;
}
and drawGrid like this:
public void drawGrid(Bitmap bmp)
{
//updatePointPerUnit(); //??
using (Graphics g = Graphics.FromImage(bmp))
{
...
...
...
}
}
Now the Bitmap with the grid should immediately show up in the PictureBox.
As mentioned a Graphics object is a tool to change an associated Bitmap. To pick it up the Bitmap should be assigned to the PictureBoxe's Image.
Also note, that unless your PictureBox has no Border, there is a small difference between the outer size (aka Bounds) and the inner size, the ClientRectangle / ClientSize. The Image should have the ClientSize
You may wonder why your original code doesn't work? After all an Image is a reference type, so changing it, as you did should be enough..
But looking deeper into the source code we find the reason:
The PictureBox's Image is a property and in its setter there is a call to InstallNewImage:
public Image Image {
get {
return image;
}
set {
InstallNewImage(value, ImageInstallationType.DirectlySpecified);
}
}
The same call is also in a few other places like Load or in the setter of ImageLocation. But changing the Image behind the scene alone will not force the PictureBox to make that call. A Refresh() should also do it.. And, as you found out, resizing it will also cause the PictureBox to pick up the changed data in the Image Bitmap..
The easiest way to force updating is simply to invalidate the control.
timer = new Timer();
timer.Interval = 200; //refreshes every 200 ms
timer.Tick += (sender,e) => targetImageBoxbox.Invalidate();
timer.Start();

Specifying Duration of sound(tone) created with WaveTone() in NAudio

I want to play a sound(tone) at specified volumes and frequencies but want the duration of playback fixed say 2 seconds.
My code is similar to one given here.
double freq, volume;
WaveTone tone = new WaveTone(freq, volume);
stream = new BlockAlignReductionStream(tone);
output = new DirectSoundOut();
output.Init(stream);
output.Play();
I tried to use latency in DirectSoundOut() above but it did not work as desired. I have to change freq and volume dynamically for each playback.
I need to know the exact duration of playback of tone.
The WaveTone class (assuming you're using one of the ones I just googled) probably provides an endless stream of data. If you want to limit the output to a specific duration you'll need to either load a specific amount of data into another buffer/stream or modify the WaveTone class to stop producing data past the duration.
Something like this:
class WaveTone : WaveStream
{
readonly WaveFormat Format;
public readonly double Frequency;
public readonly double Amplitude;
public readonly double Duration;
readonly long streamLength;
long pos;
const double timeIncr = 1 / 44100.0;
readonly double sinMult;
public WaveTone(double freq, double amp)
: this(freq, amp, 0)
{ }
public WaveTone(double freq, double amp, double dur)
{
Format = new WaveFormat(44100, 16, 1);
Frequency = freq;
Amplitude = Math.Min(1, Math.Max(0, amp));
Duration = dur;
streamLength = Duration == 0 ? long.MaxValue : (long)(44100 * 2 * Duration);
pos = 0;
sinMult = Math.PI * 2 * Frequency;
}
public override WaveFormat WaveFormat
{
get { return Format; }
}
public override long Length
{
get { return streamLength; }
}
public override long Position
{
get { return pos; }
set { pos = value; }
}
public override int Read(byte[] buffer, int offset, int count)
{
if (pos >= streamLength)
return 0;
int nSamples = count / 2;
if ((pos + nSamples * 2) > streamLength)
nSamples = (int)(streamLength - pos) / 2;
double time = pos / (44100 * 2.0);
int rc = 0;
for (int i = 0; i < nSamples; i++, time += timeIncr, ++rc, pos += 2)
{
double val = Amplitude * Math.Sin(sinMult * time);
short sval = (short)(Math.Round(val * (short.MaxValue - 1)));
buffer[offset + i * 2] = (byte)(sval & 0xFF);
buffer[offset + i * 2 + 1] = (byte)((sval >> 8) & 0xFF);
}
return rc * 2;
}
}

Bug with repeat sine sound

What is my code:
void SpeakThreadFunction()
{
while (SpeakThreadState)
{
Speaker.Play();
Thread.Sleep(100);
Speaker.Stop()
Thread.Sleep(Interval);
}
}
//Speaker is WaveOut
And Speaker.Init is SineWaveProvider32.
public class SineWaveProvider32 : WaveProvider32
{
int sample;
public SineWaveProvider32()
{
Frequency = 1000;
Amplitude = 0.25f;
}
public float Frequency { get; set; }
public float Amplitude { get; set; }
public override int Read(float[] buffer, int offset, int sampleCount)
{
int sampleRate = WaveFormat.SampleRate;
for (int n = 0; n < sampleCount; n++)
{
buffer[n + offset] = (float)(Amplitude * Math.Sin((2 * Math.PI * sample * Frequency) / sampleRate));
sample++;
if (sample >= sampleRate) sample = 0;
}
return sampleCount;
}
}
After 10-15 iterations on my cycle, sound is stop :(. What i need to do, to my sound repeat all time?
You won't have much success trying to continually start and stop the soundcard like that. The default WaveOut buffer sizes in NAudio are 100ms long. It would be much better to open the soundcard once, and then send it portions of sine wave, followed by zeroes, to create the sound you want.

Categories