Reggae buffer
  • Priest of the Order of the Butterfly
    Priest of the Order of the Butterfly
    tolkien
    Posts: 502 from 2013/5/29
    Hello mates.
    I want to put some audio to a few things using Reggae. For now I can play sounds but would like to modify the buffer (some kind of fx) but don´t know how to get the sound buffer.
    Thanks in advance.
    MorphOS: PowerMac G5 - PowerBook G4 - MacMini.
    Classic: Amiga 1200/060 - A500 PiStorm
  • »10.11.15 - 20:54
    Profile
  • Priest of the Order of the Butterfly
    Priest of the Order of the Butterfly
    Tcheko
    Posts: 510 from 2003/2/25
    From: France
    Quote:

    tolkien wrote:
    Hello mates.
    I want to put some audio to a few things using Reggae. For now I can play sounds but would like to modify the buffer (some kind of fx) but don´t know how to get the sound buffer.
    Thanks in advance.



    Look at the MMM_Pull method. It has a buffer pointer to fetch the data to. You'll get the data but out of the processing pipeline of Reggae. Use a memory stream to feed the data back to audio.output.

    This method isn't really 'smart' because such filter should in fact be inserted directly in the processing pipeline of Reggae.

    When you instanciate a pipeline with NewMediaObjectTags, Reggae does all the 'magic' by itself. It figures out what is needed to decode a stream of data:

    [ file.stream -> (some black decoding magic) ] -> output to connect to something usefull

    Generaly, you connect the returned object to an audio.output object that pulls the data to feed the audio driver.

    Then, if you want to apply a filter to the stream, you have to create a custom Reggae class that will be inserted between the NewMediaObjectTags and the .output.

    [file.stream -> (decoding magic) ] -> custom.filter -> audio.output

    Here is an expunged custom class taken from SoundBankster. It will not compile or work as is. You'll need to figure out the missing bits here and there.

    At least, it features mostly everything needed to create a custom Reggae class for audio. Hope this help.

    Code:

    #define __NOLIBBASE__

    #define SYSTEM_PRIVATE
    #include <exec/tasks.h>

    #include <classes/multimedia/sound.h>
    #include <proto/intuition.h>
    #include <proto/utility.h>
    #include <proto/multimedia.h>
    #include <math.h>


    #include "bankster_custom.h"
    #include "mcc_deck.h"
    #include "utility.h"
    #include "log.h"


    extern struct Library *SysBase, *IntuitionBase, *UtilityBase, *MultimediaBase;
    Class *customClass;

    IPTR Dispatcher(void);
    const struct EmulLibEntry Gate = {TRAP_LIB, 0, (void(*)(void))customDispatcher};

    struct Data
    {
    LONG channels;
    LONG samplerate;
    LONG bitsperchannel;
    LONG volume;
    };

    ULONG FormatTable[2] = { MMFC_AUDIO_INT16, 0 };

    Class *CreateClass(void)
    {
    Class *cl;

    if ((cl = MakeClass(NULL, (STRPTR)"multimedia.class", NULL, sizeof(struct customData), 0)))
    {
    cl->cl_Dispatcher.h_Entry = (HOOKFUNC)&Gate;
    cl->cl_UserData = NULL;
    }

    customClass = cl;
    return cl;
    }

    void DeleteClass(void)
    {
    if (customClass) FreeClass(customClass);
    }

    IPTR New(Class *cl, Object *obj, struct opSet *msg)
    {
    Object *newobj = NULL;

    if ((obj = (Object*)DoSuperMethodA(cl, obj, (Msg)msg)))
    {
    struct customData *d = (struct customData*)INST_DATA(cl, obj);
    struct TagItem *tag, *tagptr = msg->ops_AttrList;


    /* Master mixing output */
    if(DoMethod(obj, MMM_AddPort, 0))
    {
    DoMethod(obj, MMM_SetPort, 0, MMA_Port_Type, MDP_TYPE_INPUT);

    /* Line mixing output */
    if(DoMethod(obj, MMM_AddPort, 1))
    {
    DoMethod(obj, MMM_SetPort, 1, MMA_Port_Type, MDP_TYPE_OUTPUT);
    DoMethod(obj, MMM_SetPort, 1, MMA_Port_FormatsTable, &FormatTable);
    DoMethod(obj, MMM_SetPort, 1, MMA_Port_Format, MMFC_AUDIO_INT16);

    /* defaults */
    d->samplerate = 44100;
    d->channels = 2;
    d->volume = 65536;

    while ( (tag = NextTagItem(&tagptr)) != NULL)
    {
    switch(tag->ti_Tag)
    {
    case MMA_Sound_SampleRate:
    d->samplerate = tag->ti_Data;
    break;
    case MMA_Sound_Channels:
    d->channels = tag->ti_Data;
    break;
    case MMA_Sound_Volume:
    d->volume = tag->ti_Data;
    break;
    }
    }
    newobj = obj;
    }
    }
    }
    if (!newobj) CoerceMethod(cl, obj, OM_DISPOSE);
    return (IPTR)newobj;
    }

    IPTR Dispose(Class *cl, Object *obj, Msg msg)
    {
    struct Data *d = INST_DATA(cl, obj);

    return DoSuperMethodA(cl, obj, msg);
    }

    IPTR customSet(Class *cl, Object *obj, struct opSet *msg)
    {
    struct customData *d = INST_DATA(cl, obj);
    int tagcount = 0;
    struct TagItem *tag, *tagptr = msg->ops_AttrList;

    while ((tag = NextTagItem(&tagptr)))
    {
    switch(tag->ti_Tag)
    {
    }
    }

    tagcount += DoSuperMethodA(cl, obj, (Msg)msg);

    return tagcount;
    }

    IPTR customGet(Class *cl, Object *obj, struct opGet *msg)
    {
    struct customData *d = INST_DATA(cl, obj);
    int rv = FALSE;
    ULONG *store;

    store = msg->opg_Storage;

    DoMethod(obj, MMM_LockObject);

    switch (msg->opg_AttrID)
    {
    case MMA_Sound_BitsPerSample:
    *store = 16;
    rv = TRUE;
    break;

    case MMA_Sound_Channels:
    *store = d->channels;
    rv = TRUE;
    break;

    case MMA_Sound_SampleRate:
    *store = d->samplerate;
    rv = TRUE;
    break;

    case MMA_ObjectName:
    *store = (LONG)"custom class of your own";
    rv = TRUE;
    break;
    default:
    rv = (DoSuperMethodA(cl, obj, (Msg)msg));
    }
    DoMethod(obj, MMM_UnlockObject);

    return rv;
    }

    IPTR customSetup(__unused Class *cl, __unused Object *obj, __unused struct mmopSetup *msg)
    {
    BOOL status = FALSE;

    switch(msg->Port)
    {
    case 0:
    status = TRUE;
    break;
    case 1:
    status = TRUE;
    break;
    }

    return status;
    }

    IPTR customPull(Class *cl, Object *obj, struct mmopPull *msg)
    {
    struct customData *d = INST_DATA(cl, obj);
    LONG bytes;

    bytes = DoMethod(obj, MMM_PrePull, msg->Port, (ULONG)msg->Buffer, msg->Length);

    if (bytes == MMM_PREPULL_NOT_DONE)
    {

    }

    DoMethod(obj, MMM_PostPull, msg->Port, (ULONG)msg->Buffer, bytes);

    return bytes;
    }

    IPTR customGetPort(Class *cl, Object *obj, struct mmopGetPort *msg)
    {
    struct customData *d = INST_DATA(cl, obj);
    ULONG res = FALSE;

    DoMethod(obj, MMM_LockObject);

    switch(msg->Attribute)
    {
    case MMA_Sound_BitsPerSample:
    *msg->Storage = 16;
    res = TRUE;
    break;

    case MMA_Sound_Channels:
    *msg->Storage = d->channels;
    res = TRUE;
    break;

    case MMA_Sound_SampleRate:
    *msg->Storage = d->samplerate;
    res = TRUE;
    break;

    case MMA_Sound_Volume:
    *msg->Storage = d->volume;
    res = TRUE;
    break;

    case MMA_StreamPosBytes:
    case MMA_StreamLength:
    case MMA_StreamSeekable:
    case MMA_ErrorCode:
    res = GetAttr(msg->Attribute, obj, msg->Storage);
    break;

    default:
    res = DoSuperMethodA(cl, obj, (Msg)msg);
    break;
    }

    DoMethod(obj, MMM_UnlockObject);

    return res;
    }

    IPTR customDispatcher(void)
    {
    Class *cl = (Class*)REG_A0;
    Object *obj = (Object*)REG_A2;
    Msg msg = (Msg)REG_A1;

    switch (msg->MethodID)
    {
    case OM_NEW: return (customNew(cl, obj, (struct opSet*)msg));
    case OM_DISPOSE: return (customDispose(cl, obj, msg));
    case OM_SET: return (customSet(cl, obj, (struct opSet*)msg));
    case OM_GET: return (customGet(cl, obj, (struct opGet*)msg));
    case MMM_Setup: return (customSetup(cl, obj, (struct mmopSetup*)msg));
    case MMM_Pull: return (customPull(cl, obj, (struct mmopPull*)msg));
    case MMM_GetPort: return (customGetPort(cl, obj, (struct mmopGetPort*)msg));
    default: return (DoSuperMethodA(cl, obj, msg));
    }
    }
    Quelque soit le chemin que tu prendras dans la vie, sache que tu auras des ampoules aux pieds.
    -------
    I need to practice my Kung Fu.
  • »11.11.15 - 07:43
    Profile Visit Website
  • Priest of the Order of the Butterfly
    Priest of the Order of the Butterfly
    tolkien
    Posts: 502 from 2013/5/29
    Hi Tcheko!
    I understand the process. Would be interesting to have a reggae method to insert this kind of magic.
    Will try your example later.
    Thanks for the example and for SoundBankster. Great work!
    MorphOS: PowerMac G5 - PowerBook G4 - MacMini.
    Classic: Amiga 1200/060 - A500 PiStorm
  • »11.11.15 - 08:06
    Profile
  • Priest of the Order of the Butterfly
    Priest of the Order of the Butterfly
    Tcheko
    Posts: 510 from 2003/2/25
    From: France
    Quote:

    tolkien wrote:
    Hi Tcheko!
    I understand the process. Would be interesting to have a reggae method to insert this kind of magic.
    Will try your example later.
    Thanks for the example and for SoundBankster. Great work!


    Ha. Forgot to mention that you need to connect the input of your custom class to the source and the output to your output object. :)

    That's how you insert something in the Reggae processing pipeline.

    Keep us informed of your progress!
    Quelque soit le chemin que tu prendras dans la vie, sache que tu auras des ampoules aux pieds.
    -------
    I need to practice my Kung Fu.
  • »11.11.15 - 08:11
    Profile Visit Website