Can i use sample or only stream? in documentation said that BASS_Mixer_StreamAddChannel can give HMUSIC, HSTREAM or HRECORD.
I'm afraid it isn't currently possible to use samples with mixers; you have to use streams, eg. BASS_StreamCreateFile rather than BASS_SampleLoad. If you have some sample data that you want to play mulitple times simultaneously, then you will need a separate stream for each simultaneous playback. If it is a PCM WAV file, then you could simply use duplicate BASS_StreamCreateFile calls without much effect on performance. If the file is encoded (eg. MP3 or OGG) then a more efficient option is to pre-decode the sample data to memory and use custom streams to play that, basically reproducing what happens when using samples. That could be done something like this...
// decoding a file to memory...
decoder=BASS_StreamCreateFile(FALSE, filename, 0, 0, BASS_STREAM_DECODE|BASS_STREAM_PRESCAN); // create a stream to decode a file
datalen=BASS_ChannelGetLength(decoder, BASS_POS_BYTE); // get the length
data=malloc(datalen); // allocate a buffer for the sample data
BASS_ChannelGetData(decoder, data, datalen); // decode the sample data
BASS_ChannelGetInfo(decoder, &info); // get format info if not already known/hardcoded
BASS_StreamFree(decoder); // free the decoder
...
// sample playback state structure
typedef {
BYTE *data;
DWORD length;
DWORD pos;
} SAMPLESTATE;
...
// playing sample data via a mixer...
SAMPLESTATE *state=malloc(sizeof(SAMPLESTATE)); // allocate state, and initialize it...
state->data=data;
state->length=datalen;
state->pos=0;
stream=BASS_StreamCreate(info.freq, info.chans, BASS_STREAM_DECODE, SampleStreamProc, state); // create a stream for the sample data
BASS_ChannelSetSync(stream, BASS_SYNC_FREE, 0, FreeSyncProc, state); // set a sync to free the state
BASS_Mixer_StreamAddChannel(mixer, stream, BASS_STREAM_AUTOFREE); // plug it into a mixer
...
DWORD CALLBACK SampleStreamProc(HSTREAM handle, void *buffer, DWORD length, void *user)
{
SAMPLESTATE *state=(SAMPLESTATE*)user;
if (length>state->length-state->pos) length=state->length-state->pos; // limit it to what's remaining
memcpy(buffer, state->data+state->pos, length); // copy the sample data to the stream buffer
state->pos+=length; // advance the position marker
if (state->pos==state->length) length|=BASS_STREAMPROC_END; // reached the end
return length;
}
void CALLBACK FreeSyncProc(HSYNC handle, DWORD channel, DWORD data, void *user)
{
free(user); // free the state
}
Please see the documentation for details on the aforementioned functions.
Sound play only once, when click on the button on the first time.
I fix this usin
//button pressed
- (IBAction)playSound:(id)sender {
BASS_Mixer_StreamAddChannel(mixer, chan2, 0);
BASS_Mixer_ChannelSetPosition(chan2, 0, BASS_POS_BYTE);
}
I feel ashamed for this code. But i not understand how right work with sound.
That looks fine; you're rewinding the source so that it can be played again. It would be better to call BASS_ChannelSetPosition before BASS_Mixer_StreamAddChannel though, so that the source is ready to go again before it's added to the mixer...
BASS_ChannelSetPosition(chan2, 0, BASS_POS_BYTE);
BASS_Mixer_StreamAddChannel(mixer, chan2, 0);
Other problem.
Short sound play with long delay. Wery long. One second or more after press button.
The delay shouldn't be that long, but the mixer will add some delay due to its playback buffer (see BASS_CONFIG_BUFFER). You could try enabling the BASS_ATTRIB_NOBUFFER option (via BASS_ChannelSetAttribute) to avoid the delay. As always, please see the documentation for details on that option.
Simple question. I add into mixer recording from microphone
//Button for recording voice pressed
- (IBAction)recordVoice:(id)sender {
BASS_RecordInit(-1);
rchan=BASS_RecordStart(info.freq, 1, MAKELONG(0, 5), 0, 0);
BASS_Mixer_StreamAddChannel(mixer, rchan, 0);
}
It's work fine and in the final file i have voice mixed with background track.
But how disable sound output while recording? I record and hear my vice.
You would need 2 mixers in that case: one for playback and one for file writing. You could have the output mixer feeding the file mixer, and add the recording to the file mixer too. There are a couple of ways that you could feed the output mix into the file mixer: you could set a DSP function (DSPPROC) on the mixer and have that feed the data to a "push" stream (see BASS_StreamCreate) that is plugged in the file mixer, or you could use "splitter" streams. Using "splitter" streams, the flow could look something like this...
source1 -> output mixer -> playback splitter
source2 -> -> file splitter -> file mixer <- recording
source3 ->
etc
The code for that might look something like this...
outputmixer=BASS_Mixer_StreamCreate(freq, chans, BASS_STREAM_DECODE); // create the output mixer
filemixer=BASS_Mixer_StreamCreate(recfreq, recchans, BASS_STREAM_DECODE); // create the file mixer (with same format as recording)
playsplit=BASS_Split_StreamCreate(outputmixer, 0, 0); // create a splitter to play the output mix
filesplit=BASS_Split_StreamCreate(outputmixer, BASS_STREAM_DECODE|BASS_SPLIT_SLAVE, 0); // create a splitter to feed the output mix to the file mixer
BASS_Mixer_StreamAddChannel(filemixer, filesplit, BASS_MIXER_NORAMPIN); // plug it into the file mixer
BASS_Mixer_StreamAddChannel(filemixer, recording, 0); // plug in the recording too
BASS_ChannelPlay(playsplit, FALSE); // start the output
Note that the file mixer won't be processed automatically, as it isn't being played (directly or indirectly). BASS_ChannelGetData will need to be used in a worker thread or timer to process it. A worker thread's processing loop could look something like this...
while (!quit) {
DWORD avail=BASS_ChannelGetData(recording, NULL, BASS_DATA_AVAILABLE); // check amount of data in recording buffer
if (avail) { // got some
BYTE buf[20000]; // processing buffer
BASS_ChannelGetData(filemixer, buf, min(avail, sizeof(buf))); // process some data
} else
Sleep(50); // wait a bit
}