jack-ifying shell-fm?

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

jack-ifying shell-fm?

ken restivo-3
I found a great console Last.FM client:
http://nex.scrapping.cc/shell-fm/

But, it uses libao, not JACK.

I'd love to be able to listen to it whilst having my softsynths going too-- fun to play along with.

There's one function in shell-fm that does the audio output (called, of course, "output"). Simple enough. But it's not callback-based: there's a thread that shuffles data from the network out to the libao interface. I've been looking at it for a while, and I still don't understand how this libao stuff works. I find the JACK example code ("simple-client.c") a lot simpler to understand.

But, minus all the libao stuff, it looks like output() is just allocating a buffer and shoving samples into it... OK. But how to glue that to a jack-style process() callback? If the output() function dumps stuff into a buffer, and proces() is accessing that asynchronously, that just seems like a disaster waiting to happen.

What's involved in jack-ify'ing this app? Do I have to try to retrofit shell-fm to support a callback mode of operating? Or is there some well understood way to glue these together? Or is there some way to make jack "push" the bytes out using the thread model that shell-fm uses, instead of a callback model?

Sorry for, ah, not knowing JACK, but this seems like it should be simple and I'm just missing something obvious.

-ken
-------------

static enum mad_flow output(
                void * data,
                const struct mad_header * head,
                struct mad_pcm * pcm) {
        struct stream * ptr = (struct stream *) data;

        unsigned nchan = pcm->channels, rate = pcm->samplerate;
        register unsigned nsample = pcm->length;
        mad_fixed_t * left = pcm->samples[0], * right = pcm->samples[1];
        char *stream, *stream_ptr;

        head = NULL;

        if((signed) rate != ptr->fmt.rate || (signed) nchan != ptr->fmt.channels) {
                ptr->fmt.rate = rate;
                ptr->fmt.channels = nchan;
                if(ptr->device != NULL)
                        ao_close(ptr->device);
                ptr->device = ao_open_live(ptr->driver_id, & ptr->fmt, NULL);

                if(NULL == ptr->device) {
                        fprintf(stderr, "Unable to open device. %s.\n", strerror(errno));
                        return MAD_FLOW_BREAK;
                }
        }

        stream_ptr = stream = malloc(pcm->length * (pcm->channels == 2 ? 4 : 2));
       
        while(nsample--) {
                signed int sample;

                sample = scale(* left++);
                *stream_ptr++ = (sample & 0xFF);
                *stream_ptr++ = (sample >> 8) & 0xFF;

                if(nchan == 2) {
                        sample = scale(* right++);
                        *stream_ptr++ = (sample & 0xFF);
                        *stream_ptr++ = (sample >> 8) & 0xFF;
                }
        }
        ao_play(ptr->device, stream, pcm->length * (pcm->channels == 2 ? 4 : 2));
        free(stream);

        if(killed)
                return MAD_FLOW_STOP;

        return MAD_FLOW_CONTINUE;
}

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel
Reply | Threaded
Open this post in threaded view
|

Re: jack-ifying shell-fm?

Andrzej Szombierski
On Tue, 20 Nov 2007, Ken Restivo wrote:

> I found a great console Last.FM client:
> http://nex.scrapping.cc/shell-fm/
>
> But, it uses libao, not JACK.
>
> I'd love to be able to listen to it whilst having my softsynths going too-- fun to play along with.
>
> There's one function in shell-fm that does the audio output (called, of course, "output"). Simple enough. But it's not callback-based: there's a thread that shuffles data from the network out to the libao interface. I've been looking at it for a while, and I still don't understand how this libao stuff works. I find the JACK example code ("simple-client.c") a lot simpler to understand.
>
> But, minus all the libao stuff, it looks like output() is just allocating a buffer and shoving samples into it... OK. But how to glue that to a jack-style process() callback? If the output() function dumps stuff into a buffer, and proces() is accessing that asynchronously, that just seems like a disaster waiting to happen.
>
> What's involved in jack-ify'ing this app? Do I have to try to retrofit shell-fm to support a callback mode of operating? Or is there some well understood way to glue these together? Or is there some way to make jack "push" the bytes out using the thread model that shell-fm uses, instead of a callback model?
>
> Sorry for, ah, not knowing JACK, but this seems like it should be simple and I'm just missing something obvious.
>

A simple solution would be to use bio2jack (or perhaps libjackasyn) to
access JACK using blocking I/O calls. Internally bio2jack uses a
ringbuffer to pass data to the jack thread.
Alternatively, it's quite straightforward to code a simple jack process()
callback which reads from a ringbuffer (<jack/ringbuffer.h>) and
replace the ao_play call with a ringbuffer 'write' operation. The
ringbuffer implementation ensures that the threads are properly
synchronized. A similar scenario, which involves recording instead of
playback is implemented in the example jackrec client.

--
:: Andrzej Szombierski :: [hidden email] :: http://kuku.eu.org ::
:: [hidden email]  :: radio bez kitu :: http://bezkitu.com ::


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel
Reply | Threaded
Open this post in threaded view
|

Re: jack-ifying shell-fm?

ken restivo-3
On Wed, Nov 21, 2007 at 12:32:19PM +0100, Andrzej Szombierski wrote:

> On Tue, 20 Nov 2007, Ken Restivo wrote:
>
> > I found a great console Last.FM client:
> > http://nex.scrapping.cc/shell-fm/
> >
> > But, it uses libao, not JACK.
> >
> > I'd love to be able to listen to it whilst having my softsynths going too-- fun to play along with.
> >
> > There's one function in shell-fm that does the audio output (called, of course, "output"). Simple enough. But it's not callback-based: there's a thread that shuffles data from the network out to the libao interface. I've been looking at it for a while, and I still don't understand how this libao stuff works. I find the JACK example code ("simple-client.c") a lot simpler to understand.
> >
> > But, minus all the libao stuff, it looks like output() is just allocating a buffer and shoving samples into it... OK. But how to glue that to a jack-style process() callback? If the output() function dumps stuff into a buffer, and proces() is accessing that asynchronously, that just seems like a disaster waiting to happen.
> >
> > What's involved in jack-ify'ing this app? Do I have to try to retrofit shell-fm to support a callback mode of operating? Or is there some well understood way to glue these together? Or is there some way to make jack "push" the bytes out using the thread model that shell-fm uses, instead of a callback model?
> >
> > Sorry for, ah, not knowing JACK, but this seems like it should be simple and I'm just missing something obvious.
> >
>
> A simple solution would be to use bio2jack (or perhaps libjackasyn) to
> access JACK using blocking I/O calls. Internally bio2jack uses a
> ringbuffer to pass data to the jack threadad.

Thanks! That's *really* simple:
http://bio2jack.sourceforge.net/#convert

Turns out there's an #ifdef to use OSS instead of libao, and now all I need to do is a simple bit of cut-and-paste hackery in order to create a version that does bio2jack instead!

Just what I was looking for.

Again, thanks!

-ken

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel