Playing Audio in .Net / C# - c#

I'm an experienced MFC programmer of many years, who for the more recent years has been developing commercial apps in Objective C for Mac and iOS - I'm trying to get up to speed with .Net and C# (as I'm soon going to be required to convert one of my commercial apps from Mac to PC).
I've now worked my way through a couple of books and as an exercise to get more familiar with .Net (and C#) I've decided to have a go at converting one of my none commercial apps to .Net as a learning exercise and all is going well (interface is working, data structures all good) but I need to be able to play audio.
My Mac app generates audio from a series of mathematical formula - imagine a wave generator - not quite the same but similar. On the Mac I generate the audio as 16 bit signed raw audio, use Core Audio to setup audio output routing and then get a callback whenever a new buffer of audio is required for the audio routing (so I can generate the audio on the fly).
I need to do the same on the PC. Unfortunately I find MSDN documentation to be a case of "Can't see the wood for the trees" as there is such a vast amount of documentation. I can find classes that will let me load and play mp3/wav etc files, but I need to generate the audio realtime. Can anyone point me in the right direction to find something that will allow me to fill buffers on the fly as it plays them?
Thx

I have used this sample in several projects with good results. It is basically a .Net wrapper for Windows Waveform Audio API using P/Invoke.
Other choices:
NAudio
Sound Player class from .Net framework

I have created a class that can play audio given Stream derivate as an input. So if you are able to pack your sound-generator into the Stream compatible interface, it could be suitable for you.
How I did it - I used unmanaged waveOut* methods from old Windows multimedia API, and handled the playback from there.
Other options - that I am aware of - use waveOut directly, from this: http://windowsmedianet.sourceforge.net/ or write your own DirectShow source filter, but that might be too complicated, since it has to be written in c++.
If you are interested in giving my component a try, I can make it available to you at no charge, since I need it beta tested (I only used it in several of my projects).
EDIT:
Since there are 6 upvotes to the question, I am offering my component free of charge (if you find useful) here: http://dl.dropbox.com/u/10020780/SimpleAudioPlayer.zip
Maybe you can reflect on it :)

I use Audiere to accomplish this and find it works very well.
It's a C++ lib really, but there are a set of bindings available for C#.
For more info, see the question I asked.

You should have a look at FMOD which allows this kind of operation and much more. It is also cross platform which can be interested if you are also working on a mac.

Alvas.Audio has 3 audio players: Player
player.FileName = "123.mp3";
player.Play();
PlayerEx
public static void TestPlayerEx()
{
PlayerEx plex = new PlayerEx();
plex.Done += new PlayerEx.DoneEventHandler(plex_Done);
Mp3Reader mr = new Mp3Reader(File.OpenRead("in.mp3"));
IntPtr format = mr.ReadFormat();
byte[] data = mr.ReadData();
mr.Close();
plex.OpenPlayer(format);
plex.AddData(data);
plex.StartPlay();
}
static void plex_Done(object sender, DoneEventArgs e)
{
if (e.IsEndPlaying)
{
((PlayerEx)sender).ClosePlayer();
}
}
and RecordPlayer
public static void TestRecordPlayer()
{
RecordPlayer rp = new RecordPlayer();
rp.PropertyChanged += new PropertyChangedEventHandler(rp_PropertyChanged);
rp.Open(new Mp3Reader(File.OpenRead("in.mp3")));
rp.Play();
}
static void rp_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case RecordPlayer.StateProperty:
RecordPlayer rp = ((RecordPlayer)sender);
if (rp.State == DeviceState.Stopped)
{
rp.Close();
}
break;
}
}

Related

How to find USB HID DevicePath?

I've been working on USB HID Device in embedded system and C# for a while. I decided to use USBHid library in C#. I got the ideal result with this library. But I have a problem. While defining the USB in the USBHid library, the following code is sufficient in the project of the library that I found on the internet.
public UsbHidDevice Device;
Device = new UsbHidDevice(vvvv,pppp);
However, when I use the same library, it asks me for an expression in the following format.
public UsbHidDevice Device; string vidandpid =
"\\hid#vid_0000&pid_0000&mi_00#a&0&000000000&1&0000#{eeof37d0-1963-47k4-aa41-74476db7uf49}";
Device = new UsbHidDevice(vidandpid);
I adapted this format for my own HID device, but without success. How should this string expression be? I am open to your views. Thank you from now.
How to find USB HID DevicePath?
I gave up on USBHID library and found solution with HidLibrary library. As far as I understand, HidLibrary falls short on some issues.
Here I am sharing the C# code that I linked with HidLibrary. Thank you for all the replies.
device = HidDevices.Enumerate(VendorID, ProductID).FirstOrDefault();
if (device != null)
{
device.OpenDevice();
device.Inserted += DeviceAttachedHandler;
device.Removed += DeviceRemovedHandler;
device.MonitorDeviceEvents = true;
device.ReadReport(myfunction);
}
else { RtBox_Feedback.AppendText("NOT DEVICE!"); }
\\hid#vid_0000&pid_0000&mi_00#a&0&000000000&1&0000#{eeof37d0-1963-47k4-aa41-74476db7uf49} - is a device interface for the {eeof37d0-1963-47k4-aa41-74476db7uf49} interface. It is almost always unique and semi-random for each device. It also may change if yore put device in another USB slot. This string may be used as path to open this "file" with CreateFile Win32 API and talk with device by means of interface-specific IOCTLs. More info here.
For HID devices Windows have another device interface GUID - GUID_DEVINTERFACE_HID - {4D1E55B2-F16F-11CF-88CB-001111000030}
You can use CM_Get_Device_Interface_ListW or SetupDiGetClassDevs/SetupDiEnumDeviceInterfaces/SetupDiGetDeviceInterfaceDetail APIs to enumerate device interfaces by interface GUID or by device Instance ID.
Mentioned "USBHid library in C#" may already have code that doing such enumeration and filtering by HID deivce VID/PID but I cannot say it for sure since you haven't added link to the code of this library. :)

WPF Live-Regions just for Narrator?

I have a textblock (ContentTextBlock) with AutomationProperties.LiveSettings="Assertive". I'm just testing and checking how useful this feature is. And... am disappointed so far.
private void Button_Click(object sender, RoutedEventArgs e)
{
ContentTextBlock.Text += " test";
var peer = UIElementAutomationPeer.FromElement(ContentTextBlock);
if(peer == null)
{
peer = UIElementAutomationPeer.CreatePeerForElement(ContentTextBlock);
peer.RaiseAutomationEvent(AutomationEvents.LiveRegionChanged);
}
peer.RaiseAutomationEvent(AutomationEvents.LiveRegionChanged);
}
When using Narrator, this works as advertised. Whenever clicking the button, Narrator announces the TextBlock text ("test" "test test" "test test test")... But when I use NVDA or JAWS, nothing happens, although the screenreader versions are relatively up-to-date. Did they really not add any support for live-regions or am I just missing an important point?
Whilst I didn't manage to get live regions to work, I found another workaround:
Tolk by Davy Kager
Tolk is a library which can, among oterrs
Detect which supported screen reader, if any, is running
Pass strings to the screen reader's speech engine and braille.
Also has support for SAPI
To include Tolk in your C# project, download it from the link above, then include tolk.cs (from src/dotnet) in your project, and place tolk.dll (it's found in bin) in the folder with your executable (or somewhere in the PATH variable). Make sure that the dll version matches your CPU target (x86/x64). Do the same for the dlls in the lib directory. Then you can use it according to the code found in the examples folder.
PS. Tolk works on Win 7 as well, so that's a bonus. The live-regions of WPF were only supported from Win 8 on.

using an Audio Endpoint other than 'DefaultAudioEndpoint' in C#

This program is an audio visualizer for an rgb keyboard that listens to windows' default audio device. My audio setup is a bit more involved, and I use way more than just the default audio device. For instance, when I play music from Winamp it goes through the device Auxillary 1 (Synchronous Audio Router) instead of Desktop Input (Synchronous Audio Router) which I have set as Default. I'd like to be able change the device that the program listens to for the visualization.
I found in the source where the audio device is declared; Lines 32-36 in CSCoreAudioInput.cs:
public void Initialize()
{
MMDevice captureDevice = MMDeviceEnumerator.DefaultAudioEndpoint(DataFlow.Render, Role.Console);
WaveFormat deviceFormat = captureDevice.DeviceFormat;
_audioEndpointVolume = AudioEndpointVolume.FromDevice(captureDevice);
}
The way that I understand it from the documentation, the section MMDeviceEnumerator.DefaultAudioEndpoint(DataFlow.Render, Role.Console) is where Windows gives the application my default IMMEndpoint "Desktop Input."
How would I go about changing DefaultAudioEndpoint?
Further Reading shows a few ways to get an IMMDevice, with DefaultAudioEnpoint being one of them. It seems to me that I'd have to enumerate the devices, and then separate out Auxillary 1 (Synchronous Audio Router) using PKEY_Device_FriendlyName. That's a bit much for me, as I have little to no C# experience. Is there an easier way to go about choosing a different endpoint? Am I on the right track? or am I missing the mark completely?
Also, what is the difference between MMDevice and IMMDevice? The source only seems to use MMDevice while all the Microsoft documentation references IMMDevice.
Thanks.
I DID IT!
I've found why the program uses MMDevice rather than IMMDevice. The developer has chosen to use the CSCore Library rather than Windows' own Core Audio API.
From continued reading of the CSCore MMDeviceEnumerator Documentation, it looks like I'll have to make a separate program that outputs all endpoints and their respective Endpoint ID Strings. Then I can substitute the DefaultAudioEndpoint method with the GetDevice(String id) method, where String id is the ID of whichever Endpoint I chose from the separate program.
To find the the Endpoint I wanted, I wrote this short program to find all the info I wanted:
static void Main(string[] args)
{
MMDeviceEnumerator enumerator = new MMDeviceEnumerator();
MMDeviceCollection collection = enumerator.EnumAudioEndpoints(DataFlow.Render,DeviceState.Active);
Console.WriteLine($"\nNumber of active Devices: {collection.GetCount()}");
int i = 0;
foreach (MMDevice device in collection){
Console.WriteLine($"\n{i} Friendly name: {device.FriendlyName}");
Console.WriteLine($"Endpoint ID: {device.DeviceID}");
i++;
}
Console.ReadKey();
}
This showed me that the Endpoint I wanted was item number 3 (2 in an array) on my list, and instead of using GetDevice(String id) I used ItemAt(int deviceIndex).
MMDeviceEnumerator enumerator = new MMDeviceEnumerator();
MMDeviceCollection collection = enumerator.EnumAudioEndpoints(DataFlow.Render,DeviceState.Active);
MMDevice captureDevice = collection.ItemAt(2);
However in this case, the program was not using captureDevice to bring in the audio data. These were the magic lines:
_capture = new WasapiLoopbackCapture(100, new WaveFormat(deviceFormat.SampleRate, deviceFormat.BitsPerSample, i));
_capture.Initialize();
I found that WasapiLoopbackCapture uses Windows' default device unless changed, and the code was using DefaultAudioEndpoint to get the properties of the default device. So I added
_capture.Device = captureDevice;
//before
_capture.Initialize();
And now the program properly pulls the audio data off of my non-default audio endpoint.
I had been asked to solve a similar type of problem this week. Although there are a few librarys to do this I was specifically asked to do this for "non ish" programmers so I developed this in PowerShell.
Powershell default audio device changer - Github
Maybe you can alter it to your needs.

Play audio from a stream in UWP

I'm basically asking the same thing that was asked here, however, that question was asked 8 years ago and the answer is no longer applicable to UWP.
I have a audio stream with http://someurl.com/stream that streams in audio/ogg format. I would like to be able to play that from an UWP app.
I see the NAudio library recommended a lot (after all, it's used in the above example), however it's very larger and has fairly lackluster documentation and very few up-to-date examples (they used to have a streaming example, but from what I'm able to download off Codeplex, it was replaced with a regular local-file player example). I'm not experience enough to make sense of the little documentation and example code they do have.
I'm honestly not even sure where to begin. I've never handled a stream like this (or any stream). Maybe the NAudio library isn't the way to go?
Code would be appreciated, but even pointers to sources where I could read up on playing such stream would be very helpful as my google-fu has failed me.
Thank you.
EDIT:
private void PlayMedia() {
System.Uri manifestUri = new Uri("http://amssamples.streaming.mediaservices.windows.net/49b57c87-f5f3-48b3-ba22-c55cfdffa9cb/Sintel.ism/manifest(format=m3u8-aapl)");
var mediaPlayer = new Windows.Media.Playback.MediaPlayer();
~~~~~~~~~~~~ -> "'Media Player' does not contain a constructor that takes 0 arguments."
mediaPlayer.Source = MediaSource.CreateFromUri(manifestUri);
mediaPlayer.Play();
}
but I can't get the MediaPlayer class to work. It says for example the x.Play() doesn't exist.
You have not posted your code segment. So I could not locate the problem of Visual Studio alerting "doesn't exist" accurately. If you want to use "MediaPlayer" class please add Windows.Media.Core and Windows.Media.Playback namespace at first. And you could reference the following code implementing a basic mediaplayer.
using Windows.Media.Core;
using Windows.Media.Playback;
......
private void PlayMedia()
{
System.Uri manifestUri = new Uri("http://amssamples.streaming.mediaservices.windows.net/49b57c87-f5f3-48b3-ba22-c55cfdffa9cb/Sintel.ism/manifest(format=m3u8-aapl)");
var mediaPlayer = new MediaPlayer();
mediaPlayer.Source = MediaSource.CreateFromUri(manifestUri);
mediaPlayer.Play();
}
The error message of Media Player does not contain a constructor that takes 0 arguments is means that there is no constructor with no arguments in the MediaPlayer class. Please try use the full name of constructor with namespace.
var mediaPlayer = new Windows.Media.Playback.MediaPlayer();

I need a GUI for my project in c++

I need a GUI system that contain:
a tree list that each item of list linked to a view and when I click on a Item open the view
for next step
I want to insert to each view some grids.
I see a demo example named :dockpanelsuite http://sourceforge.net/projects/dockpanelsuite/
there is a explorer and multi document
I think that I can change it to my requirment.
but this is in C# and I need something in C++.
if is same sample in MFC ,or I can combine them?
what about performace and stability?
thanks herzl
use QT. It's comprehensive, has a lot of tutorials in the web out there, is portable and is in C++.
Qt is better than MFC for a number of reasons including:
. > 1.It is open source
2.It is cross platform. It works on Linux, some mobile devices and
Mac
OSX. This makes it easier to port
programs to other platforms.
> 3.Qt is much easier to use and learn that MFC.
> 4.Above all Qt is well documented.
MFC is too big library. Go for win32 if you only want simple GUI
Win32++ as also a nice little library for windows only development.
You could start creating a new MFC SDI App in the App Wizard pick the Visual Studio Project Style, you will need to use the Document/View architecture.
With the generated App you could work you way to have in the left docking pane a derived ListControl class from CMFCListCtrl.
class CMyListCtrl : public CMFCListCtrl
{
// Your stuff goes here....
public:
DECLARE_MESSAGE_MAP()
afx_msg void OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult);
}
in the implementation file you could handle the click event with something like this..
BEGIN_MESSAGE_MAP(CMyListCtrl, CMFCListCtrl)
ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, &CMyListCtrl::OnLvnItemchanged)
END_MESSAGE_MAP()
void CMyListCtrl::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
POSITION p = GetFirstSelectedItemPosition();
int nSelected = GetNextSelectedItem(p);
if (nSelected != -1)
{
CString strText = GetItemText(nSelected, 0);
// we open the document.....
CMainFrame *pFrame = static_cast<CMainFrame *> (AfxGetMainWnd());
CWinApp *app = AfxGetApp();
app->OpenDocumentFile(strText,FALSE);
pFrame->ShowJobsProperties ();
}
*pResult = 0;
}

Categories

Resources