Re: Help decide what will be in Synthizer 1.0
@camlorn
Sorry for getting back to you so late, I didn't have enough energy to even open one more tab in firefox, needless to speak about checking the forum...
first, thanks for thinking about the multiple soundcard issue, a good audio library should have that eventually, I suppose. Plus, this way we could integrate it better and more readily in nvda add-ons, knowing they won't be stuck with the default cpl chosen output device, as then synthiser would be able to play through NVWave, right?
Next, about the recording thingi, no, am sure as hell not thinking a full voice chat solution, better leave that to skype/discord/whatever nowadays. Furthermore, if I want to dabble in such things, there are a lot of voip libs for .net, and if I would somehow want to go even lower level than that, I could just manually record, apply some open source noise reduction filters, then use grpc directly to handle the efficient networking and all that stuff, as I heard somewhere grpc is particularly good at streamming stuff through the network at low latency.
And, as I saw, we both agree a buffer the next few seconds of audio coming through the mik approach is too limited and pointless to include in 1.0, so I came up with something else, now that I have more time to write and am properly on a computer keybord this time. p.s. This is, as far as I remember, the first time I am using the forum from the computer, I always used the phone to post everything around here.
you know, originality and creativity are good most of the time, but there always comes a time where it's better to copy existing concepts, if not code directly, rather than reinventing the wheel whenever you need a wheel...just for the sake of it.
So, as I am even now using bass for my audio stuff, I'd recommend you copy something of its recording design.
it goes basically something like this: In stead of providing just a record_start, record_stop and pause and a buffer, which would be good for starters, it lets the user choose what they want to do with the sample data, you guessed it, through a callback.
I don't know your API very well, but I'll write here how I'd like it to be, and that's similar to what bass does.
bool RecordInit(
unsigned int deviceID, //when initialising the recording subsystem, you will need to be able to select the input device as well.
//so, -1 could be the user default, set in control pannel or wherever,
//0 would be first device...n-1 would be the last system accessible input device.
);
this function returns true in case recording succeeded, false and sets an error flag otherwise. In bass, we can query this with BASS_ErrorGetCode, I believe.
next, we must be able to start the recording, so...
unsigned long record_start(
DWORD frequency, //the frequency measured in, obviously, hz, at which to record. I found 44100 hz recording gives pretty good quality
DWORD channels, //the number of channels. 1 for mono, 2 for stereo, and so on...though I think more than stereo would be pointless
record_callback proc, //here is where the user specifies their callback function to run whenever the system decides to...see below for some other comments on that
//if null, the library will provide some default behaviour, again, see below if I can write so much without my computer crashing.
void *userdata //some extra data passed by the caller to the callback. This pointer would be passed as it is in a dedicated parameter.
);
This will, in bass, return a valid channel ID on success, and a null handle on failure. Again, we query the error with BASS_ErrorGetCode.
In synthiser, DK, instead of the valid channel, you could return maybe a generator, and for error just return null and log the fakt the error occured and what kind...you know these things, so why am I still typing?
Now that I look at those functions, I think I don't understand really well what the docs say in some sections, so I will copy the relevant info here as is, in case you, who obviously know more about this than anyone else around here, can make use of it
**snippet**
The sample data will generally arrive from the recording device in blocks rather than in a continuous stream, so when specifying a very short period between callbacks, some calls may be skipped due to there being no new data available since the last call.
When not using a callback (proc = NULL), the recorded data is instead retrieved via BASS_ChannelGetData. To keep latency at a minimum, the amount of data in the recording buffer should be monitored (also done via BASS_ChannelGetData, with the BASS_DATA_AVAILABLE flag) to check that there is not too much data; freshly recorded data will only be retrieved after the older data in the buffer is.
**maybe not so relevant from now on, I included it here for completeness sake**
Platform-specific
Multiple simultaneous recordings can be made from the same device on Windows XP and later, but generally not on older Windows. Multiple simultaneous recordings are possible on iOS and OSX, but may not always be on Linux or Windows CE.
**end snippet.**
now, the callback shouldn't be too complicated, because the users need to be able to understand it even without documentation, that means, not too many params, OK?
So, I recommend something like this
bool record_callback(
unsigned long handle, //the handle(recording) from which this new block of data originated.
//This is here because, maybe, the user assigned the same callback for multiple recordings on multiple devices, DK why one would do that though, but the system needs to be able to handle that edgecase as well if you decide to allow it, or spicifically prohibit it in stead.
const void *buffer, //the data itself, in windows PCM format, exactly as it came from the processor.
//this could contain effects already added directly to the recording handle/generator/whatever synthiser uses for effects, before the callback could do anything
DWORD length, //the length of the buffer in memory
void *userdata, //the pointer passed before, in the record_start function.
);
This function must return true to continue recording, and false to stop it imediatly.
Now, the recording pausing, resuming, stopping and all that should be implemented in the generator, like any other audio file supported by synthiser, so to maintain uniformity or however you call that in english. Then, the buffer could be extracted from the generator as data, possibly making it be able to save to a wav file...I won't clame I know how to even suggest this be done, so I will stop speaking. Unless this is already included in synthiser?
P.S: I should really somehow find time to read the synthiser manual entirely, as I read just a bit of it and some examples. But I am making these suggestions because I think this could, finally, be a good and stable audio library and, whatever you say, I bet this would, oneday, leek in the sighted community. oops, it already did, I told a friend who works at a company, who... nevermind.
Now, I think you are going to post something like..."Why don't you use a sepparate recording library, then use the memory protocols(whenever they will appear) to pump the data into synthiser?"
well, because only synthiser knows it's systems best. What I mean through this is, let's say, for example, you are handling a huge file now, decoding it because it's, of course, in mp3, loading it in memory entirely(I'm saying this just to get the worst possible scenario), worse, applying some effects on huge parts on it, am I missing something?
In that case, I bet on all stars you don't want to continue the recording just then, while the huge file selected by the stupid user is loading, I mean, didn't he realise he started the recording previously? No matter, users are stupid, so we must cope with it.
Then, if I were using another library, the recording would get very laggy, due to not enough CPU or whatever, and, besides, not knowing the CPU load of synthiser at that moment, your lib would need to handle an external source pumping something else into it besides everything above, isn't that, just a bit, too much?
So, if the recording would be available in synthiser, you would, just maybe, try calling that callback less often till this processor hungry file is loaded, even though the buffer may get a bit large by then? Or, even better, pause the recording altogether?
well, the user will notice the possible gap/distortion/whatever in the recording during that file loading, but at least that lag won't take synthiser down maybe through an out of memory exception or whatever, and, if the computer is weak enough, the entire system along with it. So, which would be better, in your opinion? I know which would be for me.
-- Audiogames-reflector mailing list Audiogames-reflector@sabahattin-gucukoglu.com https://sabahattin-gucukoglu.com/cgi-bin/mailman/listinfo/audiogames-reflector