21 May '13 - 15:39 *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
 
   Home   Help Search Login Register  
Pages: [1]
  Reply  |  Print  
Author Topic: Recording all using sounds as one track  (Read 616 times)
roma86
Guest
« on: 28 Aug '12 - 09:53 »
Reply with quoteQuote

Hello! The Bass not have any examples for iOS and there is a problem for me.
But maybe anybody know what the way record and save to file all sound using in the current stage. How about DJ app - they keep the music from different pieces and put them on each other.

For example, in the game play background music. When player jumping, cocosdenchion can play jumping sound. Can i create new track combine background music and other music effects realtime and save it?

May be some simple code example, please.
Logged
Ian @ un4seen
Administrator
Posts: 15253


« Reply #1 on: 28 Aug '12 - 17:17 »
Reply with quoteQuote

It sounds like the BASSmix add-on may be what you want. With that, you can create a mixer and plug "decoding channels" into it, something like this...

BASS_INFO info;
BASS_GetInfo(&info); // get output device info
mixer=BASS_Mixer_StreamCreate(info.freq, 2, 0); // create a stereo mixer with the same sample rate
BASS_ChannelPlay(mixer, 0); // start it

source=BASS_StreamCreateFile(FALSE, filename, 0, 0, BASS_STREAM_DECODE|BASS_SAMPLE_FLOAT); // create a decoding channel for a file
BASS_Mixer_StreamAddChannel(mixer, source, 0); // plug it into the mixer

If you would like to write the mix to a file, you could use the BASSenc add-on, eg. BASS_Encode_StartCAFile, something like this...

encoder=BASS_Encode_StartCAFile(mixer, 'm4af', 'alac', 0, 0, "output.m4a"); // set an ALAC encoder on the mixer

Please see the documentation for details on all of the aforementioned functions.
Logged
roma86
Guest
« Reply #2 on: 29 Aug '12 - 06:21 »
Reply with quoteQuote

Hello, Ian @ un4seen and thank you. I will try to use you tip.
Logged
roma86
Guest
« Reply #3 on: 29 Aug '12 - 20:24 »
Reply with quoteQuote

Hello again!
Course i could not solve the task and brought my wrong code here. Sorry.

i have two problem.

My code:
   
BASS_Init(-1,44100,0,NULL,NULL);
   
    BASS_INFO info;
    BASS_GetInfo(&info);
    mixer=BASS_Mixer_StreamCreate(info.freq, 2, 0); // HERE note build for device, only for simulator. If remove than compile
   
    NSString *documentDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *filename = [documentDir stringByAppendingString:@"/file.m4a"];

    source = BASS_StreamCreateFile(FALSE, [filename cStringUsingEncoding:NSUTF8StringEncoding], 0, 0, BASS_STREAM_DECODE|BASS_SAMPLE_FLOAT);
    BASS_Mixer_StreamAddChannel(mixer, source, 0);
   
    BASS_Encode_StartCAFile(mixer, 'm4af', 'alac', 0, 0, [filename cStringUsingEncoding:NSUTF8StringEncoding]);//HERE create file in the right directory with right name, but only for simulator and only 28 bite

    BASS_ChannelPlay(mixer, 0);
   
    NSString *soundFileName = [[NSBundle mainBundle] pathForResource:@"ff13" ofType:@"mp3"];

    chan = BASS_StreamCreateFile(FALSE, [soundFileName cStringUsingEncoding:NSUTF8StringEncoding], 0, 0, BASS_SAMPLE_LOOP);
    BASS_ChannelPlay(chan, FALSE);

1. Code not build for device, but build and work for simulator. Problem in the line:
mixer=BASS_Mixer_StreamCreate(info.freq, 2, 0);
Error for this line:

there are three just like that errors
2. On the simulator project play sample
BASS_ChannelPlay(chan, FALSE);
Create file in the right directory with right file name
BASS_Encode_StartCAFile(mixer, 'm4af', 'alac', 0, 0, [filename cStringUsingEncoding:NSUTF8StringEncoding]);
but file size only 28 bite and it's no contain sound.
Maybe it's problem simulator, but on the device i have not test this questions because project not build.
Logged
Ian @ un4seen
Administrator
Posts: 15253


« Reply #4 on: 30 Aug '12 - 14:16 »
Reply with quoteQuote

To fix the first problem, you need to add the "Accelerate" framework to your project. Please see the iOS thread for a full list of required frameworks:

   www.un4seen.com/forum/?topic=10910

Regarding the second problem, it looks like you are attempting to play the output file (rather than the source audio file) via the mixer. The code should probably look like this instead...

BASS_Init(-1,44100,0,NULL,NULL);
   
    BASS_INFO info;
    BASS_GetInfo(&info);
    mixer=BASS_Mixer_StreamCreate(info.freq, 2, 0);
   
    NSString *soundFileName = [[NSBundle mainBundle] pathForResource:@"ff13" ofType:@"mp3"];
    chan = BASS_StreamCreateFile(FALSE, [soundFileName cStringUsingEncoding:NSUTF8StringEncoding], 0, 0, BASS_STREAM_DECODE|BASS_SAMPLE_FLOAT|BASS_SAMPLE_LOOP);
    BASS_Mixer_StreamAddChannel(mixer, chan, 0);

    NSString *documentDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *filename = [documentDir stringByAppendingString:@"/file.m4a"];
    BASS_Encode_StartCAFile(mixer, 'm4af', 'alac', 0, 0, [filename cStringUsingEncoding:NSUTF8StringEncoding]);

    BASS_ChannelPlay(mixer, 0);

Note that BASS_ChannelPlay is only called on the mixer, and the audio file is played through the mixer via BASS_Mixer_StreamAddChannel.
Logged
roma86
Guest
« Reply #5 on: 2 Sep '12 - 09:32 »
Reply with quoteQuote

Hi Ian! Thank you again for helping me every time.
I want say, that if i finish this project with your tips, i get you my projects file and you can include it to downloaded file for iOS as example simple using BASS. This can help when meeting with the library.

You are right and now i can create right file with new mix track.
But i have problem again.
Can i use sample or only stream? in documentation said that BASS_Mixer_StreamAddChannel can give HMUSIC, HSTREAM or HRECORD.
if i create sample
HSAMPLE sampleTest = BASS_SampleLoad(FALSE, [shortSound cStringUsingEncoding:NSUTF8StringEncoding], 0, 0, 1, BASS_SAMPLE_FLOAT);
and create channel
chan2 = BASS_SampleGetChannel(sampleTest, TRUE);
last return HCHANNEL and not usable for mixer.

My project will have one background track, some (two or three) extra tracks, and more short samples.

Ok. i try use short sound without create sample, with creating stream
//this is short sound. true way use sample, but i not understand how.
NSString *shortSound = [[NSBundle mainBundle] pathForResource:@"stuk" ofType:@"wav"];
chan2 = BASS_StreamCreateFile(FALSE, [shortSound cStringUsingEncoding:NSUTF8StringEncoding], 0, 0, BASS_STREAM_DECODE|BASS_SAMPLE_FLOAT);

//this is main track, it is work and write into mix file fine.
NSString *soundFileName = [[NSBundle mainBundle] pathForResource:@"ff13" ofType:@"mp3"];
chan = BASS_StreamCreateFile(FALSE, [soundFileName cStringUsingEncoding:NSUTF8StringEncoding], 0, 0, BASS_STREAM_DECODE|BASS_SAMPLE_FLOAT|BASS_SAMPLE_LOOP);

//add main track into mixer it's work fine
BASS_Mixer_StreamAddChannel(mixer, chan, 0);

There is a button, clicking on which i play short sound.
//button pressed
- (IBAction)playSound:(id)sender {
    BASS_Mixer_StreamAddChannel(mixer, chan2, 0);
}
This way have many problem and i feel that this is a way to curve the wrong way and I dunce
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.

Other problem.
Short sound play with long delay. Wery long. One second or more after press button.
If i using sample
HSAMPLE sampleTest = BASS_SampleLoad(FALSE, [shortSound cStringUsingEncoding:NSUTF8StringEncoding], 0, 0, 1, BASS_SAMPLE_FLOAT);
chan2 = BASS_SampleGetChannel(sampleTest, TRUE);
//button pressed
- (IBAction)playSound:(id)sender {
    BASS_ChannelPause(chan2);
}
It work fast and good.

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.
Tried
BASS_ChannelSetAttribute(rchan, BASS_ATTRIB_VOL, 0);
it not help me. In the mixer file voice volume also 0.

Logged
Ian @ un4seen
Administrator
Posts: 15253


« Reply #6 on: 3 Sep '12 - 17:23 »
Reply with quoteQuote

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
}
Logged
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines