Processing audio file in memory with lib sox - c++

I am trying to process audio file in memory with SOX C++ API and I stuck at the very beginning. The goal is to load an audio file from disk, apply few effects (tempo/gain adjustments) in memory. Here is the code I started with, but I receive a strange error when creating out stream:
formats: can't open output file `': No such file or directory
What could be an issue here? I am testing it on Mac. Here is the code:
#include <iostream>
#include <sox.h>
#include <assert.h>
int main() {
sox_format_t * in, *out;
sox_effect_t * e;
sox_init();
in = sox_open_read("/path/to/file.wav", NULL, NULL, NULL);
sox_format_t *out_format = (sox_format_t *)malloc(sizeof(sox_format_t));
memcpy(out_format, in, sizeof(sox_format_t));
char * buffer;
size_t buffer_size;
out = sox_open_memstream_write(&buffer, &buffer_size, &in->signal, NULL, "sox", NULL);
//chain = sox_create_effects_chain(&in->encoding, &out->encoding);
//e = sox_create_effect(sox_find_effect("input"));
return 0;
}

sox_open_memstream_write() uses either fmemopen() or open_memstream() depending on the parameters you pass.
Some (or all) versions of OSX do not have these functions.
The same is true for Windows.
You can find the relevant code in file src/formats.c, function open_write(), look for the #ifdef HAVE_FMEMOPEN conditionals.

Related

How to load file font into RAM using C/C++ and SDL2?

Accordingly to the ''best practices'' I have learned, we should load the resources we need to our programs into RAM, avoiding unnecessary requests to user's hard drive. Using SDL2, I always free image files after loading them into RAM. (File -> Surface -> Texture -> Free File/Surface). So, if I other application changes the file, my program ignores it, as the file is not in use by it anymore.
Now in lesson 16 I am learning to use the Add-on SDL_ttf.
However, using SDL_ttf addon I could not find a way to free the font.ttf file, loading it into RAM too. I can only see it through a pointer. It seems to me that the file keeps being read each time I render a text.
How can I load it into RAM, so the rendering calls a RAM position, instead of the file in HD?
Full code
#define SDL_MAIN_HANDLED
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
int G = 255;
int main (void) {SDL_SetMainReady();
int SCREEN_WIDTH = 800;
int SCREEN_HEIGHT = 600;
bool QUIT_APPLICATION = false;
SDL_Event union_Event_manager;
SDL_Color str_White_colour = {255,255,255,255};
SDL_Window * ptr_Window = nullptr;
SDL_Surface * ptr_Text_Surface = nullptr;
SDL_Surface * ptr_Main_surface = nullptr;
SDL_RWops * ptr_str_rwops = nullptr;
TTF_Font * ptr_Font = nullptr;
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
ptr_Window = SDL_CreateWindow("Lesson 16 - TrueTypeFonts", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
ptr_Main_surface = SDL_GetWindowSurface(ptr_Window);
ptr_str_rwops = SDL_RWFromFile("FreeMono.ttf", "r");
ptr_Font = TTF_OpenFontIndexRW(ptr_str_rwops, 1, 72, 0);
ptr_Text_Surface = TTF_RenderText_Solid(ptr_Font, "Hello World", str_White_colour);
while(!QUIT_APPLICATION){
while(SDL_PollEvent(&union_Event_manager) != 0 ){
if (union_Event_manager.type == SDL_QUIT) {QUIT_APPLICATION = true;}
/*END WHILE*/}
SDL_BlitSurface(ptr_Text_Surface, NULL, ptr_Main_surface, NULL);
SDL_UpdateWindowSurface(ptr_Window);
/*END WHILE*/}
TTF_CloseFont(ptr_Font);
// if called before any rendering, the app crashes, as supposed to.
// So, how free the **file** and keep using its content from RAM?
SDL_RWclose(ptr_str_rwops);
SDL_FreeSurface(ptr_Text_Surface);
SDL_FreeSurface(ptr_Main_surface);
SDL_DestroyWindow(ptr_Window);
ptr_Font = nullptr;
ptr_str_rwops = nullptr;
ptr_Text_Surface = nullptr;
ptr_Main_surface = nullptr;
ptr_Window = nullptr;
TTF_Quit();
SDL_Quit();
return (0);}
Failure 1:
Create a structure to hold information from file.
TTF_Font str_Font; // Error in compilation ''incomplete type''
str_Font = *ptr_Font;
TTF_CloseFont(ptr_Font);
ptr_Font = nullptr;
ptr_Font = &str_Font;
Reason to failure:
I misunderstood how the file works. The structure only holds information about the file, not the media itself.
This approach is useless, and crash the program just after freeing the pointer (the rendering tries to dereference a nullptr).
Failure 2:
Use built in function to free resource.
ptr_Font = TTF_OpenFontIndexRW(SDL_RWFromFile("FreeMono.ttf", "r"), 1, 72, 0);
Reason to failure:
I do not understand why, as the second argument (non-zero) specifies it should free the resource after usage. It also happens in the completed source code above, where I merely separated the functions in two lines.
Failure 3:
Create structure to hold information about pointer.
ptr_str_rwops = SDL_RWFromFile("FreeMono.ttf", "r");
str_rwops = *ptr_str_rwops;
SDL_RWclose(ptr_str_rwops); // crashes the program
ptr_str_rwops = nullptr;
ptr_str_rwops = &str_rwops; // useless: file still in use.
Reason to failure:
The structure RWops seems to not hold the file, only information about it. So it is the sum of failure 1 and 2.
Failure 4:
Tried to load file as object.
ptr_LoadObject = (TTF_Font*)SDL_LoadObject("FreeMono.ttf");
ptr_str_rwops = SDL_RWFromFile((const char *)ptr_LoadObject, "r");
Reason to failure:
This function works with shared operational system files. Wrong usage of function.
Update 2019-04-05
Failure 5
Tried to make a copy of file directly into RAM useing memcpy
long int func_discover_file_size(char* file){
long int var_file_size = 0;
FILE * ptr_file = nullptr;
ptr_file = fopen(file, "rb");
fseek(ptr_file , 0L , SEEK_END);
var_file_size = ftell(ptr_file);
fclose(ptr_file);
return var_file_size;
/*END func_discover_file_size*/}
int main (void) {
/*cut unrelated code*/
void * ptr_load_file = nullptr;
void * ptr_File_copy = nullptr;
long int var_file_size = 0;
/*cut unrelated code*/
var_file_size = func_discover_file_size("FreeMono.ttf");
// works fine and returns correct size of file.
ptr_File_copy = (char*) calloc (1, var_file_size);
// memory allocation works fine (tested)
ptr_load_file = fopen("FreeMono.ttf", "rb");
// file loaded correctly. Test with FOR LOOP shows content of file in console.
memcpy(ptr_File_copy, ptr_load_file, var_file_size);
// program crashes in line above
Reason to failure:
It looks like I do not know how to correctly use memcpy. I tried many many casts to function and pointers (void, char), tried to change type of pointers to char, void, FILE, tried to output to a third pointer...
Now I am looking for a good soul to enlight my ways... :-p
note: C tagged because SDL
While freetype (which SDL_ttf uses) will not read font more than once (which it can't, since its API doesn't provide seek functionality), SDL_ttf will not close file/RWops until font closes. You can achieve what you've described via manually loading file into memory buffer and using that memory as RWops to feed data to SDL_ttf, e.g. (no error checking, no free, etc. - this is just an example):
/* 'slurp' file (read entire file into memory buffer)
* there are multiple ways to do so
*/
SDL_RWops *file_rw = SDL_RWFromFile("font.ttf", "rb");
Sint64 file_sz = file_rw->size(file_rw);
void *membuf = malloc(file_sz);
file_rw->read(file_rw, membuf, 1, file_sz);
file_rw->close(file_rw);
/* use memory buffer as RWops */
SDL_RWops *mem_rw = SDL_RWFromConstMem(membuf, file_sz);
TTF_Font *font = TTF_OpenFontRW(mem_rw, 1, font_size);
/* free(membuf) when you're done with the font */
The secondary question about memcpy can be solved in the following way:
memcpy copies a file object, not its contents. In order to read from it:
Use fread function to read from FILE*: fread(ptr_File_copy, 1,
var_file_size, ptr_load_file) instead of memcpy.

A very odd issue with std::fclose()

I was doing some simple read/write operations on files using MS Visual Studio. Here is a simplified version of the code I wrote:
#include <cstdio>
#include <cstring>
void write_into_file(const char* filename);
int main()
{
write_into_file("settings.ini");
write_into_file("com4.ini");
return 0;
}
void write_into_file(const char* filename)
{
FILE* f = std::fopen(filename, "wb");
const char* text = "Some text I want to write...";
std::fwrite(text, 1, strlen(text), f);
std::fclose(f);
}
Whenever I run the program, it gets stuck and does not end. I debugged the code and traced into it. Turned out that all parts of the code are okay and run without any problems, except the line that contains fclose. I mean, the debugger gets stuck when it reaches that line. Why this happens and what is the problem?
EDIT :
I suspected that the problem is with the name of files, specially com4.ini. So I changed the code as follows:
#include <fstream>
#include <sys/stat.h>
void write_into_file(const char* filename)
{
std::ofstream fp(filename, std::ios::out);
if (fp.is_open())
fp.close();
struct stat info;
if (stat(filename, &info) != 0)
{
perror("An error occurred. Write permissions maybe?!!");
return;
}
FILE* f = std::fopen(filename, "wb");
const char* text = "Some text I want to write...";
std::fwrite(text, 1, strlen(text), f);
std::fclose(f);
}
The funny thing is, it writes the first file successfully. For the second file, it passes the existence check and again, gets stuck at the last line. It doesn't even throw an exception! Just remains there doing nothing...
You can't use COM4.ini as a filename, see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
Specifially
"CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. Also avoid these names followed immediately by an extension; for example, NUL.txt is not recommended. For more information, see Namespaces."
It attempts to open a serial port called COM4 instead...

Flush not invoking file change

I am writing a program where one process A reads the data appended to file by another process B.I am using ReadDirectoryChangesW for the notification.The problem is that the notification is not being generated until I close the handle in B although I am flushing contents to file using fflush.The code is a given below
File Writer:
int _tmain(int argc, _TCHAR* argv[])
{
FILE *fp;
fp=_fsopen("log.txt", "a", _SH_DENYNO);
char str[4096];
for(int i=1;i<4096;i++)
str[i]=i;
while(true){
fwrite(str,1,4096,fp);
fflush(fp);
Sleep(2000);
}
return 0;
}
File Reader:
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
#include <assert.h>
#include <share.h>
void _tmain(int argc, TCHAR *argv[])
{
FILE *fp;
fp=_fsopen("C:\\Users\\dell\\Documents\\Visual Studio 2012\\Projects\\FileWriter\\FileWriter\\log.txt", "r", _SH_DENYNO);
int last_size=0,new_size=0;
if(fp==NULL)
return ;
HANDLE m_hMonitoredDir = CreateFile(TEXT("C:\\Users\\dell\\Documents\\Visual Studio 2012\\Projects\\FileWriter\\FileWriter"), FILE_LIST_DIRECTORY,
FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL );
if ( m_hMonitoredDir == INVALID_HANDLE_VALUE )
{
DWORD dwErr = GetLastError();
printf("error");
return;
}
char szBuf[ MAX_PATH ];
DWORD dwBytesRead = 0;
int flag=0;
char *buffer;
while ( ReadDirectoryChangesW( m_hMonitoredDir, szBuf, MAX_PATH, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE,&dwBytesRead, NULL, NULL ))
{
PFILE_NOTIFY_INFORMATION pstFileNotif = (PFILE_NOTIFY_INFORMATION)( szBuf );
if ( pstFileNotif->Action == FILE_ACTION_MODIFIED )
{
char szNotifFilename[ MAX_PATH ] = { 0 };
if ( int iNotifFilenameLen = WideCharToMultiByte( CP_OEMCP, NULL,
pstFileNotif->FileName,
pstFileNotif->FileNameLength / sizeof( WCHAR ),
szNotifFilename, sizeof( szNotifFilename ) / sizeof( char ),
NULL, NULL ) )
{
if ( strcmp("log.txt", szNotifFilename ) == 0 )
{
fseek(fp, 0, SEEK_END);
new_size = ftell(fp);
fseek(fp,last_size,SEEK_SET);
int size=new_size-last_size;
buffer=new char[size+1];
fread(buffer,1,size,fp);
buffer[size]='\0';
printf("%s",buffer);
free(buffer);
}
}
}
}
}
Can anyone help me get notifications as soon as I use fflush in B ?
I don't think this is possible. According to the documentation on FILE_NOTIFY_CHANGE_LAST_WRITE (emphasis mine):
Any change to the last write-time of files in the watched directory or subtree causes a change notification wait operation to return. The operating system detects a change to the last write-time only when the file is written to the disk. For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed.
fflush() ensures that the file data is passed back to the operating system, but it does not guarantee that the data gets written to the disk, since typically a lot of caching is involved:
Buffers are normally maintained by the operating system, which determines the optimal time to write the data automatically to disk: when a buffer is full, when a stream is closed, or when a program terminates normally without closing the stream. The commit-to-disk feature of the run-time library lets you ensure that critical data is written directly to disk rather than to the operating-system buffers.
As others have said in the comments, you may be better of using named pipes for your goals, since you're only dealing with a single known file.
You can force a commit-to-disk by calling _flushall ( http://msdn.microsoft.com/en-us/library/s9xk9ehd.aspx )
or see this article ( http://support.microsoft.com/kb/148505 ) on how to force a commit-to-disk. You need to link with commode.obj to force fflush to commit-to-disk automatically.
The alternative might be to fclose the file each time, and reopen the file in append mode, if you are only doing it every 2 seconds (the overhead is small).
See here: https://jeffpar.github.io/kbarchive/kb/066/Q66052/
For us, linking with commode.obj didn't work.
However, this approach did:
When we opened our file using fopen, we included the "c" mode option as the LAST OPTION:
fopen( path, "wc") // w - write mode, c - allow immediate commit to disk
Then when you want to force a flush to disk, call
_flushall()
We made this call before calling
fclose()
We experienced the exact issue you described and this approach fixed it.
From that above site:
"Microsoft C/C++ version 7.0 introduces the "c" mode option for the fopen()
function. When an application opens a file and specifies the "c" mode, the
run-time library writes the contents of the file buffer to disk when the
application calls the fflush() or _flushall() function. "

SDL and zlib issue, cannot create valid rwops structure from zip

I have been trying to read a zip archive and load a png image from it, however i am getting not valid image format error from SDL_Image. Here is the code
#include <SDL\SDL.h>
#include <SDL\SDL_opengl.h>
#include <SDL\SDL_image.h>
#define ZLIB_WINAPI //to use zlibwapi dll
#include <zlib.h>
#include <zip.h> //minizip
#include <unzip.h> //minizip
#include <string>
SDL_RWops* readfromarchive(std::string archive, std::string filename)
{
unzFile data;
unz_file_info info;
Uint8* buffer = NULL;
SDL_RWops* rw = NULL;
data = unzOpen(archive.c_str());
unzLocateFile( data, filename.c_str(), 1 );
unzGetCurrentFileInfo( data, &info, NULL, 0, NULL, 0, NULL, 0 );
unzOpenCurrentFile( data );
buffer = (Uint8*)malloc(info.uncompressed_size);
unzReadCurrentFile( data, buffer, info.uncompressed_size );
rw = SDL_RWFromMem(buffer, info.uncompressed_size);
free(buffer);
unzClose(data);
return rw;
}
when i do this
Surf_Temp = IMG_Load_RW( readfromarchive(archive, filename) , 1);
I get the error IMG_Load_RW: %s Unsupported image format
Well, if load directly from the unzipped file it works using IMG_Load(), works when create a rwops structure through sdl and load too using
IMG_Load_RW(SDL_RWFromFile(filename.c_str(), "rb"), 1);
So the file format is fine, all zlib and minizip functions dont return any error, i check the info struct and the data is consistant with the file i am trying to load, so the error is somewhere in creating the rwops struct.
The problem is the following. You are using an RWOPs structure form SDL. In the given case you want to read from memory. But you delete the memory before your read it. The RWOPs structure will not copy the memory, it needs to remain valid until everything is read.
To solve the problem, pull the call to IMG_Load_RW before the call to free(buffer);

process video stream from memory buffer

I need to parse a video stream (mpeg ts) from proprietary network protocol (which I already know how to do) and then I would like to use OpenCV to process the video stream into frames. I know how to use cv::VideoCapture from a file or from a standard URL, but I would like to setup OpenCV to read from a buffer(s) in memory where I can store the video stream data until it is needed. Is there a way to setup a call back method (or any other interfrace) so that I can still use the cv::VideoCapture object? Is there a better way to accomplish processing the video with out writing it out to a file and then re-reading it. I would also entertain using FFMPEG directly if that is a better choice. I think I can convert AVFrames to Mat if needed.
I had a similar need recently. I was looking for a way in OpenCV to play a video that was already in memory, but without ever having to write the video file to disk. I found out that the FFMPEG interface already supports this through av_open_input_stream. There is just a little more prep work required compared to the av_open_input_file call used in OpenCV to open a file.
Between the following two websites I was able to piece together a working solution using the ffmpeg calls. Please refer to the information on these websites for more details:
http://ffmpeg.arrozcru.org/forum/viewtopic.php?f=8&t=1170
http://cdry.wordpress.com/2009/09/09/using-custom-io-callbacks-with-ffmpeg/
To get it working in OpenCV, I ended up adding a new function to the CvCapture_FFMPEG class:
virtual bool openBuffer( unsigned char* pBuffer, unsigned int bufLen );
I provided access to it through a new API call in the highgui DLL, similar to cvCreateFileCapture. The new openBuffer function is basically the same as the open( const char* _filename ) function with the following difference:
err = av_open_input_file(&ic, _filename, NULL, 0, NULL);
is replaced by:
ic = avformat_alloc_context();
ic->pb = avio_alloc_context(pBuffer, bufLen, 0, pBuffer, read_buffer, NULL, NULL);
if(!ic->pb) {
// handle error
}
// Need to probe buffer for input format unless you already know it
AVProbeData probe_data;
probe_data.buf_size = (bufLen < 4096) ? bufLen : 4096;
probe_data.filename = "stream";
probe_data.buf = (unsigned char *) malloc(probe_data.buf_size);
memcpy(probe_data.buf, pBuffer, probe_data.buf_size);
AVInputFormat *pAVInputFormat = av_probe_input_format(&probe_data, 1);
if(!pAVInputFormat)
pAVInputFormat = av_probe_input_format(&probe_data, 0);
// cleanup
free(probe_data.buf);
probe_data.buf = NULL;
if(!pAVInputFormat) {
// handle error
}
pAVInputFormat->flags |= AVFMT_NOFILE;
err = av_open_input_stream(&ic , ic->pb, "stream", pAVInputFormat, NULL);
Also, make sure to call av_close_input_stream in the CvCapture_FFMPEG::close() function instead of av_close_input_file in this situation.
Now the read_buffer callback function that is passed in to avio_alloc_context I defined as:
static int read_buffer(void *opaque, uint8_t *buf, int buf_size)
{
// This function must fill the buffer with data and return number of bytes copied.
// opaque is the pointer to private_data in the call to avio_alloc_context (4th param)
memcpy(buf, opaque, buf_size);
return buf_size;
}
This solution assumes the entire video is contained in a memory buffer and would probably have to be tweaked to work with streaming data.
So that's it! Btw, I'm using OpenCV version 2.1 so YMMV.
Code to do similar to the above, for opencv 4.2.0 is on:
https://github.com/jcdutton/opencv
Branch: 4.2.0-jcd1
Load the entire file into RAM pointed to by buffer, of size buffer_size.
Sample code:
VideoCapture d_reader1;
d_reader1.open_buffer(buffer, buffer_size);
d_reader1.read(input1);
The above code reads the first frame of video.