@database "sound_dtc" @Node Main "sound_dtc.doc" @toc "Includes_&_Autodocs/Main" @{" --background-- " Link "--background--"} @{" sound.datatype() " Link "sound.datatype()"} @EndNode @Node "--background--" "sound.datatype/--background--" @{b} HISTORY@{ub} The datatypes system was introduced by AmigaOS 3.0 (V39) in 1992. It was designed to manage different formats for several kind of data. This includes loading, saving, viewing, printing, embedding, but is also open to new methods that cannot be considered by the main system. There is a wide range of usages for datatypes: Importing and exporting of unusual file formats, converting between different formats, exchanging data between different applications via clipboard, embedding of "living" objects in html/amigaguide/text documents, databases of general data files, applications that want to include pictures or sounds (e.g. games) without the need to write own file loaders and viewers. But in practice the datatypes are used only rarely. Picture managers, html viewers, image processors use their own systems of import/export plugins, which are not exchangeable. Datatypes are only covered by another plugin. The same with music programs and sound processors. But why? One reason is surely that the datatypes system does support too few features of many file formats. picture.datatype does not handle more than 256 colors, the remapping algorithms are not very good and so on, the original sound.datatype does not support stereo sounds and more than 8 bit sample resolution, not to speak about multi-octave instruments. Crunching is not explicitly supported by the system. But there are replacements for the datatypes.library, for picture.datatype and for sound.datatype that fixes some of the problems. Unfortunately the effort about the datatypes V45 project declined in the present. But especially in the sound.datatype there remains much that is to do. @{b} OVERVIEW@{ub} This is only a conception for an improvement of the current sound.datatype replacement (V41.4). It should show an interface that covers the applications hard disk recording/replaying/editting and simple import/export but with much less memory consumption than the conception used up to now. The things described here under the version number 42 are only thoughts. Nothing of it is implemented. Other than some people are afraid of, the datatype does not replace any sound application, e.g. it does not implement any edit function or effect operator by itself. But it makes functions available which allow programs to do this independent to sample format and storage type (disk/ram/hotlink(in future)). @{b} TERMS@{ub} Some terms that I will use frequently in the following document: @{u}main sound.datatype@{uu} the datatype library called "sound.datatype" @{u}sub-sound.datatype@{uu} a sub-class of "sound.datatype" acts as a format import/export plugin usually @{u}application format@{uu} a sample word format that can be used by an application this must be a non-interleaved pulse code format of 8, 16 or 32 bits @{u}custom format@{uu} the format that is supported by a sub-sound.datatype examples are "svx.datatype", "wav.datatype" @{b} VIEWS OF PROGRAMMING@{ub} This document looks a bit complicated because it covers several views of programming as well as several levels of every view. For the programmer of the @{u}main sound.datatype@{uu} it shows how all parts work together and what things have to be put in the main part of the system. My goal is that one invest a bit more work in the main sound.datatype in order to make programming of sub-sound.datatypes on the one side and usage of sound.datatype for import/export etc. on the other side as easy as possible. This is senseful because the sound.datatype has to be written @{b}once@{ub}, whereas sub-sound.datatypes and sound.datatype applications are written again and again. Why to blow them up with generic code? For the programmer of a @{u}sub-sound.datatype@{uu} it is important to know which things have to be implemented for handling custom file formats and which things can be left out - this depends on how exotic your format is. Three cases are covered: 1. Your format is very common. It is structured in header data, sample data, possibly foot data and it uses pulse code modulated data inside. The only thing to do then is to supply the attributes that describes that structure. If editting direct on disk is wished, re-sizing of sample file should also be supported. Reading and writing will be done by the main sound.datatype. 2. Your format is regularly structured but the sample word interpretation is uncommon. This is probably very seldom and occurs with formats that uses a fixed-ratio crunching algorithm such as CCITT µ law (whereas fibonacci delta is still not possible since I restricted the sample word size to multiples of bytes and fibonacci delta requires the knowledge of the predecessing sample word) or uncommon aligned bit data, such as 12 bit data hold in 16 bit words but in the lower bits 0-11 instead of 4-15. Additional to the things to do in case one you have to implement SDTM_ConvertSample that converts between your custom format and one of the application formats. To simplify your work you can convert all data to a format with enough precision (but not more) and let SDTM_ConvertSample of the super class (which is the main sound.datatype class in most cases) do the rest. 3. Your format is absolutely cryptic, e.g. encoded or crunched (mpeg). You have to implement SDTM_OpenSample, SDTM_CloseSample, SDTM_ReadSample, SDTM_WriteSample and possibly SDTM_SeekSample, SDTM_ProcessSample by yourself. This guarants a maximum of abstraction and a maximum of work for you :-) For the programmer of a @{u}sound application@{uu} the document explains which attributes and methods are available to do the operations on samples mentioned above. Again, there are three levels of using sound.datatype dependent on how much control you want. 1. An application like a game that want to make some noise from time to time will use the sound.datatype as it would do with V40. A little example sketch in Pseudo-PasiCembler :-) and without error checking: obj := NewDTObject ("example.smp", DTA_GroupID : "soun", DONE); DoMethod (obj, STM_PLAY); DisposeDTObject (obj); 2. An application that has sample processing as its main task will want to load sample data in its own buffers or to leave it on disk. The former way was to create a datatype object and ask for its sample buffer. This way should be avoided in future, since it requires to have the double amount of memory for the sample available while loading. Loading, saving and processing of sample data is very similar now: (* let's load data in a sliced 16 bit sample buffer *) obj := NewDTObject ("example.smp", DTA_GroupID : "soun", SDTA_Storage : disk, DONE); GetAttrs (obj, SDTA_SampleLength : length'PTR, SDTA_Channels : channels'PTR, DONE); FOR c:=0 TO channels-1 DO (* a shortcut for DoMethod (obj, SDTM_OpenSample ...) *) sound[c].AllocateBuffer (length); handle := obj.OpenSample (SDTA_Channel : c, SDTA_WordSize : 2, DONE); buffer := sound[c].first; WHILE (buffer#NIL) AND (obj.ReadSample (handle, buffer.mem, buffer.len) # -1) DO buffer := buffer.next; END; obj.CloseSample (handle); END; DisposeDTObject (obj); 3. An application that processes sample data in one direction without jumping back and forth may use SDTM_ProcessSample which let the sub-sound.datatype choose the most efficient way. The higher efficiency must be buyed with some more application code - you must write a private sound.datatype sub-class which handles the operation. But this class can also be used to handle the sounds within your application and is then a very handy solution. (* normally it is sufficient to code one dispatcher for one application and re-use it for loading, saving and processing *) PROCEDURE PrivateSoundDTDispatcher (cl : IClassPtr; obj : DatatypeObject; msg : Msg) : ANYPTR; VAR data : PrivateSoundDTDataPtr; PROCEDURE OperateSample (msg : SDTP_OperateSamplePtr); BEGIN WITH data.sound[PrivateHandlePtr(msg.handle).channel] AS sound DO sound.InsertBottom (AllocBuffer(msg.length)); CopyMem (msg.memory, sound.buffer.last.mem, msg.length); END; END OperateSample; PROCEDURE OpenSample (msg : SDTP_OpenSamplePtr) : ANYPTR; VAR handle : PrivateHandlePtr; BEGIN handle := AllocMem (PrivateHandle'SIZE); handle.channel := TGET (msg.tagList, SDTA_Channel, 0); RETURN handle; END OpenSample; PROCEDURE CloseSample (msg : SDTP_CloseSamplePtr); BEGIN FreeMem (msg.handle, PrivateHandle'SIZE); END CloseSample; BEGIN data := InstData (cl, obj); IF KEY msg.methodId OF SDTM_OperateSample THEN OperateSample (msg) END; OF SDTM_OpenSample THEN RETURN OpenSample (msg) END; OF SDTM_CloseSample THEN CloseSample (msg) END; OF Op_New THEN (* allocate array for channels *) END; ELSE RETURN DoSuperMethod (cl, msg, obj); END; RETURN NIL; END PrivateSoundDTDispatcher; BEGIN obj := NewDTObject ("example.smp", DTA_GroupID : "soun", SDTA_Storage : disk, DONE); GetAttrs (obj, SDTA_SampleLength : length'PTR, SDTA_Channels : channels'PTR, DONE); class := MakeClass ("sound.datatype", PrivateSoundDTDispatcher, PrivateSoundDTData'SIZE); privObj := NewDTObject (NIL, DTA_Class : class, SDTA_Channels : channels, DONE); (* after finishing the startup code this line is the thing that occurs multiple times in your application *) obj.ProcessSample (privObj, SDTA_AllChannels : TRUE, SDTA_WordSize : 2, SDTA_ProcessRead : TRUE, DONE); CLOSE DisposeDTObject (privObj); DisposeDTObject (obj); END @{b} ATTENTION@{ub} You should carefully read and try to understand the conception. Think about what you want to do with the sound.datatype and what you need if you would write a sub-sound.datatype by yourself. Then tell me what you further need to achieve this and we will discuss how to design this in a way that satisfy all the other sound.datatype users. Preferred place for this discussion is the Datatypes Association's mailing list. My favorite goal is to make any custom import/export system unnecessary. If you are author of a sound editting system you will surely vehement disagree, because you do not want to rewrite all your plugins to datatypes without getting one more feature. I know that it is very hard for programmers to say: "Ok, this seemed to be the wrong way up to here. Now let's make things completely new." You might further argue, that the future about Amiga in general and datatypes especially (-> OS 3.5) is something uncertain, and that you don't want to invest more time under this circumstances. Ok, but never forget these things: 1. The Amiga situation is how it is also because lot of programmers left the Amiga only @{u}thinking@{uu} the Amiga had an uncertain future. I'm sure it is the same fear (to be the only who supports it) that let many programmers avoid the datatypes. 2. If you ever wondered why no one contributed new plugins to your own "open" plugin system I believe the answer is, that no one is interested to invest his time in program modules which he can definitely not re-use. 3. Since custom plugin systems only cover the need of the considered program, you cannot expect to build a new standard besides the datatypes system which is given by the OS. And the datatypes system is much more open as every plugin solution I've ever seen. This is because of the intensive usage of methods and tags (the basic ideas of BOOPSI) that keeps older datatypes compatible with improved datatypes.library versions and even more let the old datatypes benefit from the enhancements. If you are one of the programmers who do not want to rewrite their plugins by now, the problem could be solved by writing datatypes that uses your plugins. In short: Give your plugins a datatypes interface instead of giving datatypes a plugin interface! Please, do not excuse any antipathy against datatypes with "too slow", "too complicated", "generally unnecessary", "too low supported" or "it's just rubbish". It's up to you to change this. Please think it over! Please! @EndNode @Node "sound.datatype()" "sound.datatype/sound.datatype" @{b} NAME@{ub} sound.datatype -- root data type for sounds. @{b} FUNCTION@{ub} The sound.datatype is the super-class for any sound related classes. @{b} METHODS@{ub} OM_NEW -- Create a new sound object. OM_GET -- Obtain the value of an attribute. OM_SET -- Set the values of multiple attributes. OM_UPDATE -- Update the values of multiple attributes. OM_DISPOSE -- Dispose of a sound object. GM_LAYOUT -- Layout the object and notify the application of the title and size. GM_HITTEST -- Determine if the object has been hit with the mouse. GM_HELPTEST -- Determine if the mouse pointer is over the object. GM_GOACTIVE -- Tell the object to go active. On SELECTDOWN, the sound will start playing. GM_HANDLEINPUT -- Handle input. Currently input (other than SELECTDOWN) doesn't affect the sound. GM_RENDER -- Cause the graphic to render. GM_DOMAIN -- Ask the object about its min/nom/max size. DTM_TRIGGER -- Cause an event to occur. Currently the only trigger events are STM_PLAY, STM_STOP and STM_PAUSE. DTM_COPY -- Copy the entire sound to the clipboard as 8SVX. Starting v41 the datatype will create a 16sv or AIFF sample when a 16bit sample has been passed to it. DTM_WRITE -- Write the entire sound to a file as 8SVX. See also DTM_COPY. DTM_OBTAINDRAWINFO -- Get draw handle for DTM_DRAW. One of the following tags must be passed to the method: PDTA_Screen GA_DrawInfo DTM_DRAW -- Draw the object into the specified rastport. The tapedeck controls won't be drawn (no GadgetInfo available). DTM_RELEASEDRAWINFO -- Free handle obtained via DTM_OBTAINDRAWINFO. DTM_SELECTED -- Calculate start- and endsample of the marked area. NOTE: Do not assume anything about the objects' selectbox! DTM_CLEARSELECTED -- Clear previuously marked area. The following methods are new for V42. SDTM_OpenSample -- Obtain access to the sample data The five methods SDTM_OpenSample, SDTM_CloseSample, SDTM_ReadSample, SDTM_WriteSample, SDTM_SeekSample offers a clean way to work with the sample data without assuming anything about the internal sample format, resolution and ordering. The method SDTM_OpenSample expects a tag list where you can choose the source (SDTA_Channel, SDTA_Octave) and the format in which you want the data to be converted (SDTA_WordSize, SDTA_Signed, SDTA_Endian). The significant bits are left-aligned within every sample word. To prevent the datatype from doing unnecessary conversions, you can ask for some attributes before and pass the results here. Remember: SDTA_WordSize, SDTA_Signed, SDTA_Endian have two meanings. Once for specifying details of the custom format when calling NewDTObject() with SDTA_Storage of SDTV_Storage_Disk_#? (although SDTA_SubFormat is preferred here) and another time for specifying the format you want to get the data in (application format). SDTM_OpenSample returns a blackbox handle that must be passed to further SDTM_ReadSample, SDTM_WriteSample, SDTM_SeekSample and SDTM_CloseSample calls. It contains a Dos-FileHandle which holds FileLocation pointer in case it is a disk sample and some memory pointers if it is stored in ram (see SDTA_Storage). But this is not visible to you, and every sub-sound.datatype might store there what it want. The handle pointer is NULL if the allocation failed. You may ask, why opening is not done in one go with NewDTObject()/OM_New. One reason is that a program might want to read/write at several locations in a disk file at the same time. Ok, you could also do this by switching the locations by hand. Another reason is that a program may not want to open the file all the time, but is only interested in preventing it from deleting by locking it and transfer data only from time to time. The most important reason is that one (sub-)sound.datatype might be able to cache data, so if you read two blocks each from another channel, the datatype may cache the data of both channels (if they are interleaved on disk) from the first call and flush this cache not before the second read call is done. You see that this optimization (if it will ever be done) requires that the sound.datatype object and the handle are separated. But of course, this is still a point that must be discussed. For sub-sound.datatype programmers: Because authors of sub-sound.datatypes don't want to write the same in/out routines again and again (at least I assume this :-), sound.datatype offers to do the file access by itself. In this case you simply don't overload the SDTM_#?Sample methods and carefully implement the OM_Get method instead. SDTM_OpenSample will usually ask for the attributes SDTA_WordSize, SDTA_Endian, SDTA_Signed, SDTA_NumChannels, SDTA_NumOctaves, SDTA_BeginLoc, SDTA_WordStep, SDTA_ChannelStep. SDTM_OpenSample will then assume that this describes the sample format structure completely and let SDTM_(Read|Write)Sample do the file access for you. You may still influence the conversion by overloading SDTM_ConvertSample. SDTM_CloseSample -- quit the access to sample data Every successful call to SDTM_OpenSample must be paired with a call to SDTM_CloseSample (with the handle obtained by SDTM_OpenSample of course). SDTM_ReadSample -- read in a block of sample data from the sample storage Pass the handle, the destination memory address and the block length in number of samples. Of course, it increases the current file position, so that you can read in the complete channel by calling ReadSample again and again. Returns the number of sample words actually read or -1 if an error occured (see Dos' Read()). For sub-sound.datatype programmers: If you re-define this method, choose an application format close to your custom format, read in and convert the data in this application format. Then call SDTM_ConvertSample after reading to do the rest. SDTM_WriteSample -- write a block of sample data out to the sample storage Pass the handle, the source memory address and the block length in number of samples. Of course, it increases the current file position, so that you can write the complete channel by calling WriteSample again and again. Returns the number of sample words actually wrote or -1 if an error occured (see Dos' Write()). For sub-sound.datatype programmers: If you re-define this method, choose an application format close to your custom format, let SDTM_ConvertSample convert the data in this format and write the result in the custom format. SDTM_OperateSample -- do an operation on a block of sample data This is only for objects of private sub-classes of sound.datatype and it is neither implemented in the sound.datatype nor in any format handling sub-sound.datatype (means wav.datatype or voc.datatype etc.). It is called by SDTM_ProcessSample. Receives the handle, the source/destination memory address and the block length in number of samples. Returns the number of sample words actually operated or -1 if an error occured. SDTM_SeekSample -- move the current position Pass the handle, the new read/write position measured in sample words and the reference point (beginning, end, current; see Dos' Seek()) within the scope of the considered channel and octave. Returns the old read/write position in samples or -1 if an error occured. An error can be that the datatype does not support seeking, e.g. in chrunched sample data. SDTM_ProcessSample -- process the sample with a custom operation Using SDTM_OpenSample you decide what order of processing the sample data is used. This will be unefficient in some cases. Imagine you want to clear a part of a stereo sample. Using SDTM_OpenSample you must clear the parts in both channels separately which requires to read and write the whole clip twice. Instead of this SDTM_ProcessSample finds out the most efficient order and asks you to operate on the sample data. Therefore you must pass a datatypes object of a private sound.datatype sub-class (simply a BOOPSI sub-class of sound.datatype created with Intuition.MakeClass()) which acts as interface between the addressed sound.datatype object and your application. You may fill this private object with current data before every call to SDTM_ProcessSample, which let the private object work very close to your application. SDTM_ProcessSample will call SDTM_OpenSample, SDTM_CloseSample, SDTM_OperateSample (I avoided re-using of SDTM_ReadSample or SDTM_WriteSample to prevent confusions) of the applications private sub-sound.datatype class. This procedure is completely analogous to the SDTM_OpenSample ceremony of the format handling sub-sound.datatypes, but here it is up to the application programmer to implement the sound.datatype methods called by SDTM_ProcessSample. Further you must pass a tag list to SDTM_ProcessSample which specify the channels, the octaves, the beginning and the length of sample data to be processed. SDTA_Channel and SDTA_Octave may be used multiple times to specify more than one channel/octave to be processed in one go. The SDTA_Process#? tags are reserved for use with SDTM_ProcessSample. The method returns a boolean value indicating wether the processing could be successfully completed or not. Errors may be traditional Dos errors or the unability of the sub-sound.datatype to seek to a position within the file (e.g. crunched data). In our example SDTM_ProcessSample would select the strategy by looking at the interleave character of the sample data. If the sample words of the channels are interleaved, it loads the whole sample block by block from disk, splits every block in left and right channel, passes the extracted data to the operation supplied by the private datatypes object, packs the processed data, writes it back to the disk and goes to the next block. This is not the best procedure in this case but in general the fastest. If the sample data is not interleaved, SDTM_ProcessSample processes the channels one after the other. But in every case SDTM_ProcessSample decreases the disk accesses to one complete read and one complete write. Let me illustrate another example: You have a multi-channel sample sound on disk with the length C and you want to delete a clip of length B starting at position A in some selected channels. Obviously you have to move the block with length C-(A+B) starting at A+B to position A and fill up the rest with 0. You cannot shorten the whole sound by default, because the skipped channels keep their length. You call SDTM_ProcessSample with SDTA_ProcessBegin : A, SDTA_ProcessLength : C-A, following SDTA_Channel for each affected channel. In your private sound.datatype class you implement the following: SDTM_OpenSample calls again SDTM_OpenSample on the same channel with SDTA_ProcessBegin : A+B and stores the handle in its own handle, SDTM_ReadSample calls again SDTM_ReadSample or fills up the buffer with zeroes when the end is reached, SDTM_CloseSample frees both handles. Remember SDTM_ProcessSample is the best way for loading/saving sample data into/from application, processing data directly on disk or moving it around within the sample (known as cut/edit functions). You needn't care whether the sample data is on disk or in ram. For sub-sound.datatype programmers: If SDTM_ProcessSample is not explicitly implemented by the sub-sound.datatype, the sound.datatype has two default methods (see SDTA_ProcessByOpen) to manage this, as long as the sub-sound.datatype supply the requested tags. SDTM_ConvertSample -- convert sample data between custom and application format For sub-sound.datatype programmers: Re-define this method if your format is regularly structured but has an uncommon sample value interpretation. The method receives two buffers - the first for the application data, the second for the custom data. It receives the size of the buffers (in sample words) and a flag which shows the conversion direction (from custom to application or back), too. And last but not least it is informed about the formats of the application and the custom format via two tag lists. The tag list for the custom format is filled with some structure attributes and SDTA_SubFormat when called by SDTM_OpenSample or SDTM_ProcessSample. The direction flag is necessary in order to say to a custom SDTM_ConvertSample implementation if it should do the conversion from or to the custom format (which can normally not fully described with the sound.datatype attributes). So it is not possible to simplify the task of SDTM_ConvertSample to convert from buffer 1 to buffer 2 in every case. Make use of the conversion facilities of your superclass to benefit from further enhancements of the main sound.datatype and to prevent from returning invalid data if a future version of the main sound.datatype supports more application formats. To achieve this you can either re-use the application buffer or you have to allocate a private buffer if the sizes don't match, convert your custom data to an application format in this buffer and call the super method with the private buffer as custom buffer and pass the application buffer you received. Pass a pointer to a tag list that describes the data of your private buffer. Note: In case of re-using the application buffer, application and custom buffer are identically. SDTM_ConvertSample implementations should be able to handle this. Remark: This method replaces the SDTA_Scale attribute described in former versions of this document. SDTM_GetSubFormats -- obtain a list of all supported sub-formats Returns a pointer to an NULL terminated array of string pointers. This array is valid as long as the datatype object exists. Sub formats contains every variant that is possible within the custom format, like crunch algorithms, sample word size. E.g. the list for wav.datatype contains strings like "8 bit", "16 bit", "CCITT µ law", "fibonacci delta", "delta huffman" etc. The user can now select a sub format and the application forwards the choice (entry index) with SDTA_SubFormat to the sub-sound.datatype. @{b} TAGS@{ub} SDTA_VoiceHeader (struct @{"VoiceHeader" Link "includes/datatypes/soundclass.h/Main" 64} *) -- Set and get the base information for the sound. @{"VoiceHeader" Link "includes/datatypes/soundclass.h/Main" 64} is defined in @{"" Link "includes/datatypes/soundclass.h/Main" 0}. NOTE: sound.datatype totally ignores the information provided by the VoiceHeader. It's saved on disk at DTM_WRITE. Applicability is (ISG). SDTA_Sample (UWORD *) -- Set and get the sound data. Starting V40 the sample data does not need to be in CHIP memory. For V41 the sample should ALWAYS reside in fast memory. NOTE: The memory must be allocated with MEMF_PUBLIC flag set. It'll be freed at OM_DISPOSE by FreeVec(). New for V42: Returns NULL, if the sound is a disk sample. (see SDTA_Storage) Applicability is (ISG). SDTA_SampleLength (ULONG) -- Length of the sound data in sample frames. New for V42: If this attribute is set the sub-sound.datatype must lengthen or shorten the sound. If the length increases, the new data may be trash. Note: Setting this tag may fail. After setting you must get it to see if the new length is accepted. If you write a sub-sound.datatype, first allocate the new memory block then free the old one, otherwise you can't guarantee to fall back in the state before OM_Set. Applicability is (ISG). SDTA_Period (UWORD) -- Set and get the period of the sound. This attribute can be used to affect a playing sound. Default for this tag is 394. Applicability is (ISG). SDTA_Volume (UWORD) -- Set and get the volume of the sound. This attribute can be used to affect a playing sound. Valid range is from 0 to 64. Default for this tag is 64. Applicability is (ISG). SDTA_Cycles (UWORD) -- Set and get the number of cycles the sound will be played. Default for this tag is 1. Applicability is (ISG). The following tags are new for V40. SDTA_SignalTask (struct @{"Task" Link "includes/exec/tasks.h/Main" 23} *) -- @{"Task" Link "includes/exec/tasks.h/Main" 23} to signal when the is complete, or if SDTA_Continuous is TRUE, when the next buffer is needed. Default for this tag is NULL. Applicability is (ISG). SDTA_SignalBit (BYTE) -- @{"Signal" Link "exec/Signal()"} bit to use with SDTA_SignalTask or -1 to disable. Default for this tag is -1. Applicability is (ISG). SDTA_Continuous (BOOL) -- Used to indicate that the sound datatype will be fed a continuous stream of data. Default for this tag is FALSE. Applicability is (ISG). The following tags are new for V41. SDTA_SampleType (UBYTE) -- Set and get sampletype. The following types are currently supported: SDTST_M8S: standard 8bit mono sample. SDTST_S8S: signed 8bit stereo sample (samplewise left/right). SDTST_M16S: signed 16bit mono sample. SDTST_S16S: signed 16bit stereo sample (samplewise left/right). Default for this tag is SDTST_M8S. New for V42: Avoid this attribute. Use the single tags SDTA_WordSize and SDTA_NumChannels instead. Use the SDTM_ProcessSample method instead of accessing the data directly. This is easier for you and more future compliant. More than this it is probable that this attribute has to be removed because it is not downward compatible. Applications written for sound.datatype V40 assumes that they always get 8 bit data. They work well with this version but they will fail if sound.datatype V41 and a datatype such as the wav.datatype is present. Since they return the data in the original form, this will be e.g. 16 bit sample data if the sample file contains 16 bit data. Applicability is (ISG). SDTA_Panning (sposition) -- Set and get the stereofield. This attribute can be used to affect a playing sound. Examples: 0x08000: centers the sample in the stereofield. 0x10000: pans the sample all the way to the right. 0x00000: pans the sample all the way to the left. Default for this tag is 0x8000. Applicability is (ISG). SDTA_Frequency (ULONG) -- Set and get sample frequency. This attribute can be used to affect a playing sound. Default for this tag is EClockFreq*5/394. New for V42: Since the frequency value is hardware independent, it overrides SDTA_Period if present, too. It does overwrite the corresponding field in the VoiceHeader given by SDTA_VoiceHeader. Applicability is (ISG). The following tags are new for V42. SDTA_FixedVolume (Fixed) -- Set and get the volume of the sound. This attribute can be used to affect a playing sound. Valid range is from 0 to 0x10000. Default for this tag is 0x10000. Since this volume value is hardware independent, it overrides SDTA_Volume if present, too. It does overwrite the corresponding field in the VoiceHeader given by SDTA_VoiceHeader. Applicability is (ISG). SDTA_Storage (ULONG) -- define where the sample data should be stored SDTV_Storage_Ram - load sample data in AllocVec()ed memory block SDTV_Storage_Disk_Old - open existing file on disk SDTV_Storage_Disk_New - (re-)create new file on disk This is the key for the new procedure of loading samples into an advanced sound application. Applications that only want to output better beeps, will use SDTV_Storage_Ram or simply leave out this tag. Applications that want to load the sample data in their own data structures should use SDTV_Storage_Disk_Old to prevent the datatype from allocating sample buffer by itself. If you want to save a (big) sample you use SDTV_Storage_Disk_New. I'm not sure if one should try to implement dynamic saving via SaveDTObject/DTM_Write. It is also confusing that you must specify DTA_SourceType : DTST_File to save data to disk. What do you think? SDTV_Storage_Disk_#? are also used if you want to edit the sound directly on disk. For reading and writing data, refer SDTM_OpenSample and SDTM_ProcessSample. Default for this tag is SDTV_Storage_Ram. Applicability is (I.G). SDTA_SubFormat (ULONG) -- define variant of custom format Here you can set an index from the array you obtained with SDTM_GetSubFormats. This may influence the attributes SDTA_WordSize, SDTA_Endian, SDTA_Signed. You can still override then after setting the sub format or you can get them to get to know what the sub format index means. But you better avoid this. SDTA_WordSize (ULONG) -- size of one sample word in bytes Define the word size of one sample word. Meaning of the values is (don't laugh, it's just for completeness) 1 byte = 8 bits 2 byte = 16 bits 3 byte = 24 bits (obsolete for application formats) 4 byte = 32 bits Sample words contains always left aligned bit data, this means the most left of a word is used and is the most significant one. Other than left aligned bit data may be corrected with an overridden SDTM_ConvertSample. Note: SDTA_Bits is removed since it is too uncommon for custom formats, not to speak of application formats. Applicability is (I.G) and as parameter for SDTM_OpenSample and SDTM_ProcessSample. SDTA_Signed (BOOL) -- signed or unsigned sample words Default for this tag is TRUE or the sub-sound.datatype's choice if its format does not handle both possibilities. Applicability is (I.G) and as parameter for SDTM_OpenSample and SDTM_ProcessSample. SDTA_Endian (ULONG) -- little or big endian sample words This defines the byte ordering and is therefore only of interest for SDTA_WordSize>=2. SDTV_Endian_Little - least significant byte first (Intel) SDTV_Endian_Big - most significant byte first (Motorola) Default for this tag is SDTV_Endian_Big or the sub-sound.datatype's choice if its format does not handle both possibilities. Applicability is (I.G) and as parameter for SDTM_OpenSample and SDTM_ProcessSample. SDTA_NumChannels (ULONG) -- the number of channels supplied by the sound Default for this tag is 1. Applicability is (I.G). SDTA_NumOctaves (ULONG) -- the number of octaves which are stored as sample data Only odd numbers are accepted. 1, 3, 5 are usual, nevertheless others are possible. Overrides the vh_Octaves entry of struct VoiceHeader. Default for this tag is 1. Applicability is (I.G). SDTA_ExtraInfo (void *) -- sub-sound.datatype specific information If you know something special about the addressed sub-sound.datatype you can pass extra info. E.g. if it is an IFF datatype it may allow to add custom chunks. The structure, SDTA_ExtraInfo points to, depends on the sub-sound.datatype @{b}and@{ub} its version. This attribute is experimental and should be used very rarely. If it covers an often used topic then it is better to make this feature available to all sub-sound.datatypes. I even think SDTA_ExtraInfo is unnecessary. Since it requires the application to know the specific features of a sub-sound.datatype, it wouldn't be worse if the sub-sound.datatypes would introduce new attributes. Default for this tag is NULL. Applicability is (I.G). SDTA_PropChunk (char *) -- find additional chunks in IF files Can be used multiple times. Also Experimental. Default for this tag is NULL. Applicability is (I.G). SDTA_BeginLoc (ULONG) -- file position where the sample data starts For sub-sound.datatype programmers: Has to be implemented if SDTM_OpenSample is not redefined. With this tag a sub-sound.datatype can point to where the format specific header ends and where the real sample body starts. The file position is given in bytes. For use by sound.datatype only. Default for this tag is 0. Applicability is (..G). SDTA_WordStep (ULONG) -- number of bytes to be skipped from one word to the next For sub-sound.datatype programmers: Has to be implemented if SDTM_OpenSample is not redefined. For use by sound.datatype only. Default for this tag is SDTA_NumChannels * SDTA_ChannelStep (interleaved stereo). Applicability is (..G). SDTA_ChannelStep (ULONG) -- number of bytes to be skipped from one word to corresponding word at the next channel For sub-sound.datatype programmers: Has to be implemented if SDTM_OpenSample is not redefined. For use by sound.datatype only. Default for this tag is SDTA_WordSize (interleaved stereo). Applicability is (..G). SDTA_ProcessByOpen (BOOL) -- choose SDTM_ProcessSample emulation method For sub-sound.datatype programmers: If the sub-sound.datatype returns TRUE here, its not implemented SDTM_ProcessSample method will be emulated by OpenSample..Read/WriteSample..CloseSample calls. This becomes necessary if the considered file format is some more cryptic than normally. Otherwise this will be done by routines that learn about the sample format by getting several tags and then directly access the disk data. For use by sound.datatype only. Default for this tag is FALSE. Applicability is (..G). SDTA_ProcessBegin (ULONG) -- start point for process in sample words (counted within the considered channel/octave) Default for this tag is 0. As argument for SDTM_OpenSample and SDTM_ProcessSample only. SDTA_ProcessLength (ULONG) -- length of processed range in sample words (counted within the considered channel/octave) Default for this tag is SDTA_SampleLength. As argument for SDTM_ProcessSample only. SDTA_ProcessBlock (ULONG) -- maximum block length that is processed in one step (counted in samples) Default for this tag is 50000 or what know I (maybe user configurable). High values can relatively decrease overhead, low values can decrease memory consumption. Remember that the (sub-)sound.datatype may allocate extra buffers of the same size. As argument for SDTM_ProcessSample only. SDTA_ProcessRead (BOOL) -- fill block with sample data before operation Default for this tag is FALSE. As argument for SDTM_ProcessSample only. SDTA_ProcessWrite (BOOL) -- write back block with sample data after operation Default for this tag is FALSE. As argument for SDTM_ProcessSample only. SDTA_ProcessReverse (BOOL) -- process sample backwards Default for this tag is FALSE. As argument for SDTM_ProcessSample only. SDTA_Channel (ULONG) -- select the channel The datatype may redirect any other if the addressed channel is not available. E.g. if you want the right channel of a mono sample you get simply this one channel. The suggested meaning of the channel numbers is (but more channels are still possible): 0 - left 1 - right 2 - center 3 - back left 4 - back right 5 - subwoofer Default for this tag is 0. As argument for SDTM_OpenSample and SDTM_ProcessSample only. SDTA_Octave (LONG) -- select the octave of the instrument Because all VoiceHeader data refers to the middle octave it seems to be wise to count the octaves symmetrically to zero. That means: 1 octaves: range 0..0 3 octaves: range -1..1 5 octaves: range -2..2 Default for this tag is 0. As argument for SDTM_OpenSample and SDTM_ProcessSample only. SDTA_AllChannels (BOOL) -- process all channels Default for this tag is FALSE. As argument for SDTM_ProcessSample only. SDTA_AllOctaves (BOOL) -- process all octaves Default for this tag is FALSE. As argument for SDTM_ProcessSample only. @{b} BUGS@{ub} SDTA_Continuous wasn't supported by v41 before 41.4 -- GetDTAttrs( o, SDTA_Continuous, &val, TAG_DONE ) returned 0L. @EndNode