I am using PortAudio, and this is how I'm opening a stream for reading right now.
Pa_OpenDefaultStream(&stream, 1, 0, paFloat32, SAMPLE_RATE, SAMPLES, PaCallback, NULL);
As far as I know, this uses the microphone as input. How can I instead use a file as input? The Pa_OpenStream function strangely doesn't seem to let me enter a filename?
PortAudio is for device I/O only, such as speakers, microphones, line inputs and similar devices. To do file I/O you need another library designed for that. For example, libsoundfile, libsox or libaudiofile.
Related
I have been playing around with the libAV* family of libraries, that comes along with FFMPEG and I am learning how to implement things like encoding, decoding, muxing etc.
I came across this code : https://libav.org/documentation/doxygen/master/encode_video_8c-example.html , that encodes, YUV frames, to a file, using an encoder. In my implementation, I will change the encoder to H264 using avcodec_find_encoder(AV_CODEC_ID_H264) But I do not know, how to put this encoded data, into a proper container (.mp4) using libav libraries, so that the output file, can be played by any media player like VLC, QuickTime, etc...
Can anyone please help me on that? Every help will be greatly appreciated!
You should be able to write the frames to a file you initialize something like this:
// Have the library guess the format
AVOutputFormat *fmt = av_guess_format(NULL, "my_video.mp4", NULL);
// Set the AVOutputFormat in your output context (init not shown)
pOutFormatContext->oformat = fmt;
// Open the output, error handling not shown
avio_open2(&pOutFormatContext->pb, "my_video.mp4", AVIO_FLAG_WRITE, NULL, NULL);
// Create output stream
AVStream * outStream;
outStream = avformat_new_stream(pOutFormatContext, NULL);
// Set any output stream options you would want, example of setting the aspect ratio from the input coded 'inCodecContext' (init not shown for this)
outStream->sample_aspect_ratio.num = inCodecContext->sample_aspect_ratio.num;
outStream->sample_aspect_ratio.den = inCodecContext->sample_aspect_ratio.den;
// There may be other things you want to set like the time base, but will depend on what you're doing
// Write the header to the context, error handling not shown
avformat_write_header(pOutFormatContext, NULL);
// Dump out the format and check
av_dump_format(pOutFormatContext, 0, pOutFormatContext->filename, 1);
You then have to read the packets and encode them which it sounds like you're already doing, and then when you write to the output context it should be writing to the file in the container you specified.
I've got several USB to 422 adapters in my test system. I've used FTProg to give each adapter a specific name: Sensor1, Sensor2, etc. They will all be plugged in at power on. I don't want to hard code each adapter to a specific ttyUSBx. I want the drivers to figure out which tty it needs to use. I'm developing in C for a linux system. My first thought was to something like this in my startup code.
system("dmesg | find_usb.py");
The python script would find the devices since each one has a unique Product Description. Then using the usb tree to associate each device with its ttyUSBx. The script would then create /tmp/USBDevs which would just be a simple device:tty pairing that would be easy for the C code to search.
I've been told...DoN't UsE sYsTeM...use posix_spawn(). But I'm having problems getting the output of dmesg piped to my python script. This isn't working
char *my_args[] = {"dmesg", "|", "find_usb.py", NULL};
pid_t pid;
int status;
status = posix_spawn(&pid, "/bin/dmesg", NULL, NULL, my_args, NULL);
if(status == 0){
if(waitpid(pid, &status, 0) != -1);{
printf("posix_spawn exited: %i", status);
}
I've been trying to figure out how to do this with posix_spawn_file_actions(), but I'm not allowed to hit the peak of the 'Ballmer Curve' at work.
Thanks in advance
Instead of using /dev/ttyUSB* devices, write udev rules to generate named symlinks to the devices. For a brief how-to, see here. Basically, you'll have an udev rule for each device, ending with say SYMLINK+=Sensor-name, and in your program, use /dev/Sensor-name for each sensor. (I do recommend using Sensor- prefix, noting the initial Capital letter, as all device names are currently lowercase. This avoids any clashes with existing devices.)
These symlinks will then only exist when the matching device is plugged in, and will point to the correct device (/dev/ttyUSB* in this case). When the device is removed, udev automagically deletes the symlink also. Just make sure your udev rule identifies the device precisely (not just vendor:device, but serial number also). I'd expect the rule to look something like
SUBSYSTEM=="tty", ATTRS{idVendor}=="VVVV", ATTRS{idProduct}=="PPPP", ATTRS{serial}=="SSSSSSSS", SYMLINK+="Sensor-name"
where VVVV is the USB Vendor ID (four hexadecimal digits), PPPP is the USB Product ID (four hexadecimal digits), and SSSSSSSS is the serial number string. You can see these values using e.g. udevadm info -a -n /dev/ttyUSB* when the device is plugged in.
If you still insist on parsing dmesg output, using your own script is a good idea.
You could use FILE *handle = popen("dmesg | find_usb.py", "r"); and read from handle like it was a file. When complete, close the handle using int exitstatus = pclose(handle);. See man popen and man pclose for the details, and man 2 wait for the WIFEXITED(), WEXITSTATUS(), WIFSIGNALED(), WTERMSIG() macros you'll need to use to examine exitstatus (although in your case, I suppose you can just ignore any errors).
If you do want to use posix_spawn() (or roughly equivalently, fork() and execvp()), you'd need to set up at least one pipe (to read the output of the spawned command) – two if you spawn/fork+exec both dmesg and your Python script –, and that gets a bit more complicated. See man pipe for details on that. Personally, I would rewrite the Python script so that it executes dmesg itself internally, and only outputs the device name(s). With posix_spawn(), you'd init a posix_file_actions_t, with three actions: _adddup2() to duplicate the write end of the pipe to STDOUT_FILENO, and two _addclose()s to close both ends of the pipe. However, I myself prefer to use fork() and exec() instead, somewhat similar to the example by Glärbo in this answer.
I am trying to record audio from a microphone within a WFP (.Net Core) application.
From what I have found online, it looks like the best candidate for recording audio in .Net Core is OpenAL. You can get OpenAL from the nuget package OpenTK.NetStandard.
I was able to use an example to implement some code that makes the program play the audio as it is capturing it (a bit like an echo effect, which is why I believe the example is called Parrot).
What I am missing and cannot find any help online for, is how to save the audio to a file instead of just playing it back right away.
I think the part of the code that should save the audio to a file would go somewhere in here:
if (available_samples > 0)
{
audio_capture.ReadSamples(buffer, available_samples);
int buf = AL.GenBuffer();
AL.BufferData(buf,
ALFormat.Mono16,
buffer,
available_samples * BlittableValueType.StrideOf(buffer),
audio_capture.SampleFrequency);
AL.SourceQueueBuffer(src, buf);
StatusBarService.WriteToStatusBar("Samples consumed: " + available_samples);
if (AL.GetSourceState(src) != ALSourceState.Playing)
AL.SourcePlay(src);
}
I think the data I need to save is in one of the following variables:
buffer
buf
AL.GetSourceState(src)
I could only find 1 single example code that saves to a file, but it is in C++, 8 years old, and it does a few things I wouldn't know how to port to C#:
it creates a WAVEHEADER sWaveHeader object which holds info about the audio file
it creates vector<ALbyte> bufferVector object which is saved to file (I don't have the ALbyte type in the OpenTK.NetStandard nuget
writes to file using this method fwrite( &bufferVector[0], sizeof( ALbyte ), 1, pFile ); (where pFile is a FILE* pFile)
Has anyone been able to save audio from a microphone to file .Net Core? I really cannot find an example!
Any help would be really appreciated! :)
I need to open the default audio capture device and start recording. libsox seems to be a nice cross-platform solution. Using the binary frontend, I can just rec test.wav and the default microphone is activated.
However, when browsing the documentation, no similar functionality exists. This thread discusses precisely the same topic as my question, but doesn't seem to have reached a solution.
Where could an example of using libsox for recording from the default audio device be located?
You can record using libsox. Just set the input file to "default" and set the filetype to the audio driver (e.g. coreaudio on mac, alsa or oss on linux)
const char* audio_driver = "alsa";
sox_format_t* input = sox_open_read("default", NULL, NULL, audio_driver);
Look at some examples for more info on how to structure the rest of the code.
You need to record with alsa first and use libsox for the right format. libsox is not for recording. see example: https://gist.github.com/albanpeignier/104902
I am using VC++ 2008 express edition for C. When I try to run this:
/* Demonstrates printer output. */
#include <stdio.h>
main()
{
float f = 2.0134;
fprintf(stdprn, "This message is printed.\n\n");
fprintf(stdprn, "And now some numbers:\n\n");
fprintf(stdprn, "The square of %f is %f.", f, f*f);
/* Send a form feed */
fprintf(stdprn, "\f");
}
I get four of these errors: error C2065: 'stdprn' : undeclared identifier.
On this forum, they wrote that it works to define the printer as follows:
FILE *printer;
printer = fopen("PRN", "w");
EDIT
It builds with a warning that fopen is unsafe. When it runs the error appears:
Debug Assertion fails.
File: f:\dd\vctools\crt_bld\self_x86\crt\src\fprintf.c
Line: 55
Expression: (str != NULL)
The stdprn stream was an extension provided by Borland compilers - as far as I know, MS have never supported it. Regarding the use of fopen to open the printer device, I don't think this will work with any recent versions of Windows, but a couple of things to try:
use PRN: as the name instead of PRN (note the colon)
try opening the specific device using (for example) LPT1: (once again, note the colon). This will of course not work if you don't have a printer attached.
don't depend on a printer dialog coming up - you are not really using the WIndows printing system when you take this approach (and so it probably won't solve your problem, but is worth a try).
I do not have a printer attached, but I do have the Microsoft XPS document writer installed, s it shoulod at least bring up the standard Windows Print dialog from which one can choose the printer.
No. It wouldn't bring up a dialogue. This is because you are flushing data out to a file. And not going through the circuitous Win32 API.
The print doesn't work because the data is not proper PDL -- something that the printer could understand. For the print to work fine, you need to push in a PDL file, with language specific constructs. This varies from printer to printer, a PS printer will need you to push in a PostScript snippet, a PCL -- a PCL command-set and in case of MXDW you will have to write up XML based page description markup and create a zip file (with all resources embedded in it) i.e. an XPS file to get proper printout.
The PDL constructs are important because otherwise the printer doesn't know where to put the data, which color to print it on, what orientation to use, how many copies to print and so on and so forth.
Edit: I am curious why you are doing this. I understand portability is probably something you are trying to address. But apart from that, I'd like to know, there may be better alternatives available. Win32 Print Subsytem APIs are something that you ought to lookup if you are trying to print programmatically on Windows with any degree of fidelity.
Edit#2:
EDIT It builds with a warning that fopen is unsafe.
This is because MS suggests you use the safer versions nowadays fopen_s . See Security Enhancements in the CRT.
When it runs the error appears:
Debug Assertion fails. File: f:\dd\vctools\crt_bld\self_x86\crt\src\fprintf.c Line: 55
Expression: (str != NULL)
This is because fopen (whose return value you do not check) returns a NULL pointer. The file open failed. Also, if it did succeed a matching fclose call is called for.
There's no such thing as stdprn in ANSI C, it was a nonstandard extension provided by some compilers many years ago.
Today to print you have to use the specific APIs provided on your platform; to print on Windows you have to use the printing APIs to manage the printing of the document and obtain a DC to the printer and the GDI APIs to perform the actual drawing on the DC.
On UNIX-like OSes, instead, usually CUPS is used.
You can substitute the printer using this command with net use, see here on the MSDN kb
NET USE LPT1 \\server_name\printer_name
There is an excellent chapter on printing in DOS using the BIOS, ok, its a bit antiquated but interesting to read purely for nostalgic sake.
Onto your problem, you may need to use CreateFile to open the LPT1 port, see here for an example, I have it duplicated it here, for your benefit.
HANDLE hFile;
hFile = CreateFile("LPT1", GENERIC_WRITE, 0,NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
// handle error
}
OVERLAPPED ov = {};
ov.hEvent = CreateEvent(0, false, false, 0);
char szData[] = "1234567890";
DWORD p;
if (!WriteFile(hFile,szData, 10, &p, &ov))
{
if (GetLastError() != ERROR_IO_PENDING)
{
// handle error
}
}
// Wait for write op to complete (maximum 3 second)
DWORD dwWait = WaitForSingleObject(ov.hEvent, 3000);
if (dwWait == WAIT_TIMEOUT)
{
// it took more than 3 seconds
} else if (dwWait == WAIT_OBJECT_0)
{
// the write op completed,
// call GetOverlappedResult(...)
}
CloseHandle(ov.hEvent);
CloseHandle(hFile);
But if you insist on opening the LPT1 port directly, error checking is omitted...
FILE *prn = fopen("lpt1", "w");
fprintf(prn, "Hello World\n\f");
fclose(prn);
Hope this helps,
Best regards,
Tom.