diff options
| author | Tyler McGavran <tyler.taggerung@gmail.com> | 2022-11-06 10:24:24 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-06 08:24:24 -0700 |
| commit | e9415164bb5786f0f5052f92d59843d6549b79e4 (patch) | |
| tree | 2ca31c2211890441d74afdd19ef7a2d6eb5d7ca3 /src/audio/internal.h | |
| parent | 4e5946257d8049f421c4247d6039de94d3db83d5 (diff) | |
Lots and lots of audio code copied from SM64 (#270)
* Lots of audio decomp
* effects and playback are 100% matched
* Took some notes from the SM64 Makefile to get the right compiler
options for a couple files
* Added the audio files to rename_symbol utility
Signed-off-by: Taggerung <tyler.taggerung@gmail.com>
Diffstat (limited to 'src/audio/internal.h')
| -rw-r--r-- | src/audio/internal.h | 494 |
1 files changed, 484 insertions, 10 deletions
diff --git a/src/audio/internal.h b/src/audio/internal.h index f9bbc5593..a9aaa4628 100644 --- a/src/audio/internal.h +++ b/src/audio/internal.h @@ -1,8 +1,51 @@ #ifndef AUDIO_INTERNAL_H #define AUDIO_INTERNAL_H -#include <PR/ultratypes.h> +#include <ultra64.h> +#include "types.h" + +#define SEQUENCE_PLAYERS 4 +#define SEQUENCE_CHANNELS 48 +#define SEQUENCE_LAYERS 64 + +#define LAYERS_MAX 4 +#define CHANNELS_MAX 16 + +#define NO_LAYER ((struct SequenceChannelLayer *)(-1)) + +#define MUTE_BEHAVIOR_STOP_SCRIPT 0x80 // stop processing sequence/channel scripts +#define MUTE_BEHAVIOR_STOP_NOTES 0x40 // prevent further notes from playing +#define MUTE_BEHAVIOR_SOFTEN 0x20 // lower volume, by default to half + +#define SEQUENCE_PLAYER_STATE_0 0 +#define SEQUENCE_PLAYER_STATE_FADE_OUT 1 +#define SEQUENCE_PLAYER_STATE_2 2 +#define SEQUENCE_PLAYER_STATE_3 3 +#define SEQUENCE_PLAYER_STATE_4 4 + +#define NOTE_PRIORITY_DISABLED 0 +#define NOTE_PRIORITY_STOPPING 1 +#define NOTE_PRIORITY_MIN 2 +#define NOTE_PRIORITY_DEFAULT 3 + +#define TATUMS_PER_BEAT 48 + +// abi.h contains more details about the ADPCM and S8 codecs, "skip" skips codec processing +#define CODEC_ADPCM 0 +#define CODEC_S8 1 +#define CODEC_SKIP 2 + +#define TEMPO_SCALE TATUMS_PER_BEAT + +// TODO: US_FLOAT should probably be renamed to JP_DOUBLE since eu seems to use floats too +#define US_FLOAT(x) x ## f +#define US_FLOAT2(x) x + +// Convert u8 or u16 to f32. On JP, this uses a u32->f32 conversion, +// resulting in more bloated codegen, while on US it goes through s32. +// Since u8 and u16 fit losslessly in both, behavior is the same. +#define FLOAT_CAST(x) (f32) (s32) (x) // No-op printf macro which leaves string literals in rodata in IDO. IDO // doesn't support variadic macros, so instead we let the parameter list @@ -15,11 +58,59 @@ #define stubbed_printf(...) #endif -#define stubbed_printf_0(msg) stubbed_printf(msg) -#define stubbed_printf_1(msg, a) stubbed_printf(msg, a) -#define stubbed_printf_2(msg, a, b) stubbed_printf(msg, a, b) -#define stubbed_printf_3(msg, a, b, c) stubbed_printf(msg, a, b, c) +#define eu_stubbed_printf_0(msg) stubbed_printf(msg) +#define eu_stubbed_printf_1(msg, a) stubbed_printf(msg, a) +#define eu_stubbed_printf_2(msg, a, b) stubbed_printf(msg, a, b) +#define eu_stubbed_printf_3(msg, a, b, c) stubbed_printf(msg, a, b, c) + +struct NotePool; + +struct AudioListItem { + // A node in a circularly linked list. Each node is either a head or an item: + // - Items can be either detached (prev = NULL), or attached to a list. + // 'value' points to something of interest. + // - List heads are always attached; if a list is empty, its head points + // to itself. 'count' contains the size of the list. + // If the list holds notes, 'pool' points back to the pool where it lives. + // Otherwise, that member is NULL. + struct AudioListItem *prev; + struct AudioListItem *next; + union { + void *value; // either Note* or SequenceChannelLayer* + s32 count; + } u; + struct NotePool *pool; +}; // size = 0x10 + +struct NotePool { + struct AudioListItem disabled; + struct AudioListItem decaying; + struct AudioListItem releasing; + struct AudioListItem active; +}; + +struct VibratoState { + /*0x00, 0x00*/ struct SequenceChannel *seqChannel; + /*0x04, 0x04*/ u32 time; + /* , 0x08*/ s16 *curve; + /* , 0x0C*/ f32 extent; + /* , 0x10*/ f32 rate; + /* , 0x14*/ u8 active; + /*0x12, 0x16*/ u16 rateChangeTimer; + /*0x14, 0x18*/ u16 extentChangeTimer; + /*0x16, 0x1A*/ u16 delay; +}; // size = 0x18, 0x1C on EU +// Pitch sliding by up to one octave in the positive direction. Negative +// direction is "supported" by setting extent to be negative. The code +// extrapolates exponentially in the wrong direction in that case, but that +// doesn't prevent seqplayer from doing it, AFAICT. +struct Portamento { + u8 mode; // bit 0x80 denotes something; the rest are an index 0-5 + f32 cur; + f32 speed; + f32 extent; +}; // size = 0x10 struct AdsrEnvelope { s16 delay; @@ -54,8 +145,269 @@ struct AudioBankSound { f32 tuning; // frequency scale factor }; // size = 0x8 -struct NoteSub -{ +struct Instrument { + /*0x00*/ u8 loaded; + /*0x01*/ u8 normalRangeLo; + /*0x02*/ u8 normalRangeHi; + /*0x03*/ u8 releaseRate; + /*0x04*/ struct AdsrEnvelope *envelope; + /*0x08*/ struct AudioBankSound lowNotesSound; + /*0x10*/ struct AudioBankSound normalNotesSound; + /*0x18*/ struct AudioBankSound highNotesSound; +}; // size = 0x20 + +struct Drum { + u8 releaseRate; + u8 pan; + u8 loaded; + struct AudioBankSound sound; + struct AdsrEnvelope *envelope; +}; + +struct AudioBank { + struct Drum **drums; + struct Instrument *instruments[1]; +}; // dynamic size + +struct CtlEntry { + u8 unused; + u8 numInstruments; + u8 numDrums; + struct Instrument **instruments; + struct Drum **drums; +}; // size = 0xC + +struct M64ScriptState { + u8 *pc; + u8 *stack[4]; + u8 remLoopIters[4]; + u8 depth; +}; // size = 0x1C + +// Also known as a Group, according to debug strings. +struct SequencePlayer { + /*US/JP, EU, SH */ + /*0x000, 0x000, 0x000*/ u8 enabled : 1; + /*0x000, 0x000*/ u8 finished : 1; // never read + /*0x000, 0x000*/ u8 muted : 1; + /*0x000, 0x000*/ u8 seqDmaInProgress : 1; + /*0x000, 0x000*/ u8 bankDmaInProgress : 1; + /* 0x000*/ u8 recalculateVolume : 1; + /*0x002, 0x001, 0x001*/ u8 state; + /*0x003, 0x002*/ u8 noteAllocPolicy; + /*0x004, 0x003*/ u8 muteBehavior; + /*0x005, 0x004*/ u8 seqId; + /*0x006, 0x005*/ u8 defaultBank[1]; // must be an array to get a comparison + // to match; other u8's might also be part of that array + /*0x007, 0x006*/ u8 loadingBankId; + /* , 0x007, 0x007*/ s8 seqVariationEu[1]; + /*0x00A, 0x008*/ u16 tempo; // beats per minute in JP, tatums per minute in US/EU + /*0x00C, 0x00A*/ u16 tempoAcc; + /*0x010, 0x00C, 0x00E*/ s16 transposition; + /*0x012, 0x00E, 0x010*/ u16 delay; + /*0x00E, 0x010, 0x012*/ u16 fadeRemainingFrames; + /* , 0x012, 0x014*/ u16 fadeTimerUnkEu; + /*0x014, 0x014*/ u8 *seqData; // buffer of some sort + /*0x018, 0x018, 0x1C*/ f32 fadeVolume; // set to 1.0f + /*0x01C, 0x01C*/ f32 fadeVelocity; // set to 0.0f + /*0x020, 0x020, 0x024*/ f32 volume; // set to 0.0f + /*0x024, 0x024*/ f32 muteVolumeScale; // set to 0.5f + /* , 0x028, 0x02C*/ f32 fadeVolumeScale; + /* , 0x02C*/ f32 appliedFadeVolume; + /*0x02C, 0x030, 0x034*/ struct SequenceChannel *channels[CHANNELS_MAX]; + /*0x06C, 0x070*/ struct M64ScriptState scriptState; + /*0x088, 0x08C*/ u8 *shortNoteVelocityTable; + /*0x08C, 0x090*/ u8 *shortNoteDurationTable; + /*0x090, 0x094*/ struct NotePool notePool; + /*0x0D0, 0x0D4*/ OSMesgQueue seqDmaMesgQueue; + /*0x0E8, 0x0EC*/ OSMesg seqDmaMesg; + /*0x0EC, 0x0F0*/ OSIoMesg seqDmaIoMesg; + /*0x100, 0x108*/ OSMesgQueue bankDmaMesgQueue; + /*0x118, 0x120*/ OSMesg bankDmaMesg; + /*0x11C, 0x124*/ OSIoMesg bankDmaIoMesg; + /*0x130, 0x13C*/ u8 *bankDmaCurrMemAddr; + /*0x138, 0x140*/ uintptr_t bankDmaCurrDevAddr; + /*0x13C, 0x144*/ ssize_t bankDmaRemaining; +}; // size = 0x140, 0x148 on EU, 0x14C on SH + +struct AdsrSettings { + u8 releaseRate; + u8 sustain; + struct AdsrEnvelope *envelope; +}; // size = 0x8 + +struct AdsrState { + /*0x00, 0x00*/ u8 action; + /*0x01, 0x01*/ u8 state; + /*0x08, 0x02*/ s16 envIndex; + /*0x0A, 0x04*/ s16 delay; + /* , 0x08*/ f32 sustain; + /* , 0x0C*/ f32 velocity; + /* , 0x10*/ f32 fadeOutVel; + /* , 0x14*/ f32 current; + /* , 0x18*/ f32 target; + s32 pad1C; + /*0x1C, 0x20*/ struct AdsrEnvelope *envelope; +}; // size = 0x20, 0x24 in EU + +struct ReverbBitsData { + /* 0x00 */ u8 bit0 : 1; + /* 0x00 */ u8 bit1 : 1; + /* 0x00 */ u8 bit2 : 1; + /* 0x00 */ u8 usesHeadsetPanEffects : 1; + /* 0x00 */ u8 stereoHeadsetEffects : 2; + /* 0x00 */ u8 strongRight : 1; + /* 0x00 */ u8 strongLeft : 1; +}; + +union ReverbBits { + /* 0x00 */ struct ReverbBitsData s; + /* 0x00 */ u8 asByte; +}; +struct ReverbInfo { + u8 reverbVol; + u8 synthesisVolume; // UQ4.4, although 0 <= x < 1 is rounded up to 1 + u8 pan; + union ReverbBits reverbBits; + f32 freqScale; + f32 velocity; + s32 unused; + s16 *filter; +}; + +struct NoteAttributes { + u8 reverbVol; + u8 pan; + f32 freqScale; + f32 velocity; +}; // size = 0x10 + +// Also known as a SubTrack, according to debug strings. +// Confusingly, a SubTrack is a container of Tracks. +struct SequenceChannel { + /* U/J, EU, SH */ + /*0x00, 0x00*/ u8 enabled : 1; + /*0x00, 0x00*/ u8 finished : 1; + /*0x00, 0x00*/ u8 stopScript : 1; + /*0x00, 0x00*/ u8 stopSomething2 : 1; // sets SequenceChannelLayer.stopSomething + /*0x00, 0x00*/ u8 hasInstrument : 1; + /*0x00, 0x00*/ u8 stereoHeadsetEffects : 1; + /*0x00, ????*/ u8 largeNotes : 1; // notes specify duration and velocity + /*0x00, ????*/ u8 unused : 1; // never read, set to 0 + /* , 0x01*/ union { + struct { + u8 freqScale : 1; + u8 volume : 1; + u8 pan : 1; + } as_bitfields; + u8 as_u8; + } changes; + /*0x01, 0x02*/ u8 noteAllocPolicy; + /*0x02, 0x03, 0x03*/ u8 muteBehavior; + /*0x03, 0x04, 0x04*/ u8 reverbVol; // until EU: Q1.7, after EU: UQ0.8 + /*0x04, ????*/ u8 notePriority; // 0-3 + /*0x05, 0x06*/ u8 bankId; + /* , 0x07*/ u8 reverbIndex; + /* , 0x08, 0x09*/ u8 bookOffset; + /* , 0x09*/ u8 newPan; + /* , 0x0A*/ u8 panChannelWeight; // proportion of pan that comes from the channel (0..128) + /*0x08, 0x0C, 0x0E*/ u16 vibratoRateStart; // initially 0x800 + /*0x0A, 0x0E, 0x10*/ u16 vibratoExtentStart; + /*0x0C, 0x10, 0x12*/ u16 vibratoRateTarget; // initially 0x800 + /*0x0E, 0x12, 0x14*/ u16 vibratoExtentTarget; + /*0x10, 0x14, 0x16*/ u16 vibratoRateChangeDelay; + /*0x12, 0x16, 0x18*/ u16 vibratoExtentChangeDelay; + /*0x14, 0x18, 0x1A*/ u16 vibratoDelay; + /*0x16, 0x1A, 0x1C*/ u16 delay; + /*0x18, 0x1C, 0x1E*/ s16 instOrWave; // either 0 (none), instrument index + 1, or + // 0x80..0x83 for sawtooth/triangle/sine/square waves. + /*0x1A, 0x1E, 0x20*/ s16 transposition; + /*0x1C, 0x20, 0x24*/ f32 volumeScale; + /*0x20, 0x24, 0x28*/ f32 volume; + /* , 0x28*/ s32 pan; + /* , 0x2C*/ f32 appliedVolume; + /*0x2C, 0x30*/ f32 freqScale; + /*0x30, 0x34*/ u8 (*dynTable)[][2]; + /*0x34, ????*/ struct Note *noteUnused; // never read + /*0x38, ????*/ struct SequenceChannelLayer *layerUnused; // never read + /*0x3C, 0x40*/ struct Instrument *instrument; + /*0x40, 0x44*/ struct SequencePlayer *seqPlayer; + /*0x44, 0x48*/ struct SequenceChannelLayer *layers[LAYERS_MAX]; + /*0x54, 0x58 */ s8 soundScriptIO[8]; // bridge between sound script and audio lib. For player 2, + // [0] contains enabled, [4] contains sound ID, [5] contains reverb adjustment + /*0x5C, 0x60*/ struct M64ScriptState scriptState; + /*0x78, 0x7C*/ struct AdsrSettings adsr; + /*0x80, 0x84*/ struct NotePool notePool; +}; // size = 0xC0, 0xC4 in EU, 0xD0 in SH + +// Also known as a Track, according to debug strings. +struct SequenceChannelLayer { + /* U/J, EU, SH */ + /*0x00, 0x00*/ u8 enabled : 1; + /*0x00, 0x00*/ u8 finished : 1; + /*0x00, 0x00*/ u8 stopSomething : 1; // ? + /*0x00, 0x00*/ u8 continuousNotes : 1; // keep the same note for consecutive notes with the same sound + /* , 0x00*/ u8 unusedEu0b8 : 1; + /* , 0x00*/ u8 notePropertiesNeedInit : 1; + /* , 0x00*/ u8 ignoreDrumPan : 1; + /* , 0x01, 0x02*/ u8 instOrWave; + /*0x01, 0x02, 0x03*/ u8 status; // 0x03 in SH + /*0x02, 0x03*/ u8 noteDuration; // set to 0x80 + /*0x03, 0x04*/ u8 portamentoTargetNote; + /* , 0x05*/ u8 pan; // 0..128 + /* , 0x06, 0x07*/ u8 notePan; + /*0x04, 0x08*/ struct Portamento portamento; + /*0x14, 0x18*/ struct AdsrSettings adsr; + /*0x1C, 0x20*/ u16 portamentoTime; + /*0x1E, 0x22*/ s16 transposition; // #semitones added to play commands + // (m64 instruction encoding only allows referring to the limited range + // 0..0x3f; this makes 0x40..0x7f accessible as well) + /*0x20, 0x24, 0x24*/ f32 freqScale; + /*0x24, 0x28, 0x2C*/ f32 velocitySquare; + /*0x2C, 0x2C, 0x30*/ f32 noteVelocity; + /*0x34, 0x30, 0x34*/ f32 noteFreqScale; + /*0x38, 0x34*/ s16 shortNoteDefaultPlayPercentage; + /*0x3A, 0x36*/ s16 playPercentage; // it's not really a percentage... + /*0x3C, 0x38*/ s16 delay; + /*0x3E, 0x3A*/ s16 duration; + /*0x40, 0x3C*/ s16 delayUnused; // set to 'delay', never read + /*0x44, 0x40, 0x44*/ struct Note *note; + /*0x48, 0x44*/ struct Instrument *instrument; + /*0x4C, 0x48*/ struct AudioBankSound *sound; + /*0x50, 0x4C, 0x50*/ struct SequenceChannel *seqChannel; + /*0x54, 0x50*/ struct M64ScriptState scriptState; + /*0x70, 0x6C*/ struct AudioListItem listItem; + u8 pad2[4]; +}; // size = 0x80 + +struct NoteSynthesisState { + /*0x00*/ u8 restart; + /*0x01*/ u8 sampleDmaIndex; + /*0x02*/ u8 prevHeadsetPanRight; + /*0x03*/ u8 prevHeadsetPanLeft; + /*0x04, 0x06*/ u16 samplePosFrac; + /*0x08*/ s32 samplePosInt; + /*0x0C*/ struct NoteSynthesisBuffers *synthesisBuffers; + /*0x10*/ s16 curVolLeft; // UQ0.16 (EU Q1.15) + /*0x12*/ s16 curVolRight; // UQ0.16 (EU Q1.15) +}; +struct NotePlaybackState { + /* U/J, EU, SH */ + /*0x04, 0x00, 0x00*/ u8 priority; + /* 0x01, 0x01*/ u8 waveId; + /* 0x02, 0x02*/ u8 sampleCountIndex; + /*0x08, 0x04, 0x06*/ s16 adsrVolScale; + /*0x18, 0x08, 0x08*/ f32 portamentoFreqScale; + /*0x1C, 0x0C, 0x0C*/ f32 vibratoFreqScale; + /*0x28, 0x10, */ struct SequenceChannelLayer *prevParentLayer; + /*0x2C, 0x14, 0x14*/ struct SequenceChannelLayer *parentLayer; + /*0x30, 0x18, 0x18*/ struct SequenceChannelLayer *wantedParentLayer; + /* , 0x1C, 0x1C*/ struct NoteAttributes attributes; + /*0x54, 0x28, 0x2C*/ struct AdsrState adsr; + /*0x74, 0x4C, */ struct Portamento portamento; + /*0x84, 0x5C, */ struct VibratoState vibratoState; +}; +struct NoteSubEu { /*0x00*/ volatile u8 enabled : 1; /*0x00*/ u8 needsInit : 1; /*0x00*/ u8 finished : 1; @@ -71,15 +423,98 @@ struct NoteSub /*0x02*/ u8 bankId; /*0x03*/ u8 headsetPanRight; /*0x04*/ u8 headsetPanLeft; - /*0x05*/ u8 reverbVol; - /*0x06*/ u16 targetVolLeft; - /*0x08*/ u16 targetVolRight; + /*0x05*/ u8 reverbVol; // UQ0.7 (EU Q1.7) + /*0x06*/ u16 targetVolLeft; // UQ0.12 (EU UQ0.10) + /*0x08*/ u16 targetVolRight; // UQ0.12 (EU UQ0.10) /*0x0A*/ u16 resamplingRateFixedPoint; // stored as signed but loaded as u16 /*0x0C*/ union { s16 *samples; struct AudioBankSound *audioBankSound; } sound; }; +struct Note { + /* U/J, EU, SH */ + /*0xA4, 0x00, 0x00*/ struct AudioListItem listItem; + /* 0x10, 0x10*/ struct NoteSynthesisState synthesisState; + // The next members are actually part of a struct (NotePlaybackState), but + // that results in messy US/EU ifdefs. Instead we cast to a struct pointer + // when needed... This breaks alignment on non-N64 platforms, which we hack + // around by skipping the padding in that case. + // TODO: use macros or something instead. +#ifdef TARGET_N64 + u8 pad0[12]; +#endif + + /*0x04, 0x30, 0x30*/ u8 priority; + /* 0x31, 0x31*/ u8 waveId; + /* 0x32, 0x32*/ u8 sampleCountIndex; + /*0x08, 0x34, 0x36*/ s16 adsrVolScale; + /*0x18, 0x38, */ f32 portamentoFreqScale; + /*0x1C, 0x3C, */ f32 vibratoFreqScale; + /*0x28, 0x40, */ struct SequenceChannelLayer *prevParentLayer; + /*0x2C, 0x44, 0x44*/ struct SequenceChannelLayer *parentLayer; + /*0x30, 0x48, 0x48*/ struct SequenceChannelLayer *wantedParentLayer; + /* , 0x4C, 0x4C*/ struct NoteAttributes attributes; + /*0x54, 0x58, 0x5C*/ struct AdsrState adsr; + /*0x74, 0x7C*/ struct Portamento portamento; + /*0x84, 0x8C*/ struct VibratoState vibratoState; + u8 pad3[8]; + /* , 0xB0, 0xB4*/ struct NoteSubEu noteSubEu; +}; // size = 0xC0, known to be 0xC8 on SH + +// While this struct needs to be size 0xA0, its not clear +// what innards are necessary. All the possible options from +// SM64 are sized incorrectly so we're probably looking at some +// MK64 weirdness +struct NoteSynthesisBuffers { + s16 adpcmdecState[0x10]; + s16 finalResampleState[0x10]; + s16 panResampleState[0x10]; + s16 panSamplesBuffer[0x20]; +}; // size = 0xA0 + +/* +SM64 NoteSynthesisBuffers, kept here because I'm not sure our current +version is correct +struct NoteSynthesisBuffers { + s16 adpcmdecState[0x10]; + s16 finalResampleState[0x10]; +#ifdef VERSION_SH + s16 unk[0x10]; + s16 filterBuffer[0x20]; + s16 panSamplesBuffer[0x20]; +#else + s16 mixEnvelopeState[0x28]; + s16 panResampleState[0x10]; + s16 panSamplesBuffer[0x20]; + s16 dummyResampleState[0x10]; +#if defined(VERSION_JP) || defined(VERSION_US) + s16 samples[0x40]; +#endif +#endif +}; +*/ + +struct ReverbSettingsEU { + u8 downsampleRate; + u8 windowSize; // To be multiplied by 64 + u16 gain; +}; + +struct AudioSessionSettingsEU { + /* 0x00 */ u32 frequency; + /* 0x04 */ u8 unk1; // always 1 + /* 0x05 */ u8 maxSimultaneousNotes; + /* 0x06 */ u8 numReverbs; // always 1 + /* 0x07 */ u8 unk2; // always 0 + /* 0x08 */ struct ReverbSettingsEU *reverbSettings; + /* 0x0C */ u16 volume; + /* 0x0E */ u16 unk3; // always 0 + /* 0x10 */ u32 persistentSeqMem; + /* 0x14 */ u32 persistentBankMem; + /* 0x18, 0x1C */ u32 temporarySeqMem; + /* 0x1C, 0x20 */ u32 temporaryBankMem; +}; // 0x30 on shindou struct AudioSessionSettings { /*0x00*/ u32 frequency; @@ -110,4 +545,43 @@ struct AudioBufferParametersEU { /*0x1C*/ f32 unkUpdatesPerFrameScaled; // 3.0f / (1280.0f * updatesPerFrame) }; +struct EuAudioCmd { + union { +#if IS_BIG_ENDIAN + struct { + u8 op; + u8 arg1; + u8 arg2; + u8 arg3; + } s; +#else + struct { + u8 arg3; + u8 arg2; + u8 arg1; + u8 op; + } s; +#endif + s32 first; + } u; + union { + s32 as_s32; + u32 as_u32; + f32 as_f32; +#if IS_BIG_ENDIAN + u8 as_u8; + s8 as_s8; +#else + struct { + u8 pad0[3]; + u8 as_u8; + }; + struct { + u8 pad1[3]; + s8 as_s8; + }; #endif + } u2; +}; + +#endif // AUDIO_INTERNAL_H |
