]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge branch 'master' of git://factorcode.org/git/factor
authorJoe Groff <arcata@gmail.com>
Sun, 24 Jan 2010 20:48:17 +0000 (12:48 -0800)
committerJoe Groff <arcata@gmail.com>
Sun, 24 Jan 2010 20:48:17 +0000 (12:48 -0800)
basis/locals/locals-docs.factor
basis/unicode/case/case.factor
extra/audio/engine/engine.factor
extra/audio/engine/test/test.factor
extra/audio/vorbis/vorbis.factor [new file with mode: 0644]
extra/gpu/gpu.factor
misc/vim/syntax/factor.vim

index f44b5177e14172cb164b4899b5e7daf299d33c6a..d78905c0d7629b34c1ad3f2b132662a4ef49c6de 100644 (file)
@@ -4,7 +4,7 @@ IN: locals
 
 HELP: [|
 { $syntax "[| bindings... | body... ]" }
-{ $description "A literal quotation with named variable bindings. When the quotation is " { $link call } "ed, it will take values off the datastack values and place them into the bindings from left to right. The body may then refer to these bindings. The quotation may also bind to named variables in an enclosing scope to create a closure." }
+{ $description "A literal quotation with named variable bindings. When the quotation is " { $link call } "ed, it will take values off the datastack and place them into the bindings from left to right. The body may then refer to these bindings. The quotation may also bind to named variables in an enclosing scope to create a closure." }
 { $examples "See " { $link "locals-examples" } "." } ;
 
 HELP: [let
@@ -20,7 +20,7 @@ $nl
 { $code ":> c :> b :> a" }
 { $code ":> ( a b c )" }
 $nl
-"If any " { $snippet "var" } " name is followed by an exclamation point (" { $snippet "!" } "), that new variable is mutable. See " { $link "locals-mutable" } " for more information on mutable lexical variables." }
+"If any " { $snippet "var" } " name is followed by an exclamation point (" { $snippet "!" } "), that new variable is mutable. See " { $link "locals-mutable" } " for more information." }
 { $notes
     "This syntax can only be used inside a lexical scope established by a " { $link POSTPONE: :: } " definition, " { $link POSTPONE: [let } " form, or " { $link POSTPONE: [| } " quotation. Normal quotations have their own lexical scope only if they are inside an outer scope. Definition forms such as " { $link POSTPONE: : } " do not establish a lexical scope by themselves unless documented otherwise, nor is there a lexical scope available at the top level of source files or in the listener. " { $link POSTPONE: [let } " can be used to create a lexical scope where one is not otherwise available." }
 { $examples "See " { $link "locals-examples" } "." } ;
@@ -31,7 +31,7 @@ HELP: ::
 { $syntax ":: word ( vars... -- outputs... ) body... ;" }
 { $description "Defines a word with named inputs. The word binds its input values to lexical variables from left to right, then executes the body with those bindings in scope."
 $nl
-"If any " { $snippet "var" } " name is followed by an exclamation point (" { $snippet "!" } "), the corresponding new variable is made mutable. See " { $link "locals-mutable" } " for more information on mutable lexical variables." }
+"If any " { $snippet "var" } " name is followed by an exclamation point (" { $snippet "!" } "), the corresponding new variable is made mutable. See " { $link "locals-mutable" } " for more information." }
 { $notes "The names of the " { $snippet "outputs" } " do not affect the word's behavior. However, the compiler verifies that the stack effect accurately represents the number of outputs as with " { $link POSTPONE: : } " definitions." }
 { $examples "See " { $link "locals-examples" } "." } ;
 
@@ -41,7 +41,7 @@ HELP: MACRO::
 { $syntax "MACRO:: word ( vars... -- outputs... ) body... ;" }
 { $description "Defines a macro with named inputs. The macro binds its input variables to lexical variables from left to right, then executes the body with those bindings in scope."
 $nl
-"If any " { $snippet "var" } " name is followed by an exclamation point (" { $snippet "!" } "), the corresponding new variable is made mutable. See " { $link "locals-mutable" } " for more information on mutable lexical variables." }
+"If any " { $snippet "var" } " name is followed by an exclamation point (" { $snippet "!" } "), the corresponding new variable is made mutable. See " { $link "locals-mutable" } " for more information." }
 { $notes "The expansion of a macro cannot reference lexical variables bound in the outer scope. There are also limitations on passing arguments involving lexical variables into macros. See " { $link "locals-limitations" } " for details." }
 { $examples "See " { $link "locals-examples" } "." } ;
 
@@ -51,7 +51,7 @@ HELP: MEMO::
 { $syntax "MEMO:: word ( vars... -- outputs... ) body... ;" }
 { $description "Defines a memoized word with named inputs. The word binds its input values to lexical variables from left to right, then executes the body with those bindings in scope."
 $nl
-"If any " { $snippet "var" } " name is followed by an exclamation point (" { $snippet "!" } "), the corresponding new variable is made mutable. See " { $link "locals-mutable" } " for more information on mutable lexical variables." }
+"If any " { $snippet "var" } " name is followed by an exclamation point (" { $snippet "!" } "), the corresponding new variable is made mutable. See " { $link "locals-mutable" } " for more information." }
 { $examples "See " { $link "locals-examples" } "." } ;
 
 { POSTPONE: MEMO: POSTPONE: MEMO:: } related-words
@@ -60,7 +60,7 @@ HELP: M::
 { $syntax "M:: class generic ( vars... -- outputs... ) body... ;" }
 { $description "Defines a new method on " { $snippet "generic" } " for " { $snippet "class" } " with named inputs. The method binds its input values to lexical variables from left to right, then executes the body with those bindings in scope."
 $nl
-"If any " { $snippet "var" } " name is followed by an exclamation point (" { $snippet "!" } "), the corresponding new variable is made mutable. See " { $link "locals-mutable" } " for more information on mutable lexical variables." }
+"If any " { $snippet "var" } " name is followed by an exclamation point (" { $snippet "!" } "), the corresponding new variable is made mutable. See " { $link "locals-mutable" } " for more information." }
 { $notes "The names of the " { $snippet "outputs" } " do not affect the word's behavior. However, the compiler verifies that the stack effect accurately represents the number of outputs as with " { $link POSTPONE: M: } " definitions." }
 { $examples "See " { $link "locals-examples" } "." } ;
 
@@ -209,7 +209,7 @@ $nl
 ARTICLE: "locals-mutable" "Mutable lexical variables"
 "When a lexical variable is bound using " { $link POSTPONE: :> } ", " { $link POSTPONE: :: } ", or " { $link POSTPONE: [| } ", the variable may be made mutable by suffixing its name with an exclamation point (" { $snippet "!" } "). A mutable variable's value is read by giving its name without the exclamation point as usual. To write to the variable, use its name with the " { $snippet "!" } " suffix."
 $nl
-"Mutable bindings are implemented in a manner similar to the ML language; each mutable binding is actually an immutable binding of a mutable cell. Reading the binding automatically unboxes the value from the cell, and writing to the binding stores into it."
+"Mutable bindings are implemented in a manner similar to that taken by the ML language. Each mutable binding is actually an immutable binding of a mutable cell. Reading the binding automatically unboxes the value from the cell, and writing to the binding stores into it."
 $nl
 "Writing to mutable variables from outer lexical scopes is fully supported and has full closure semantics. See " { $link "locals-examples" } " for examples of mutable lexical variables in action." ;
 
index 79db087220e6ced846787b88826c0dea72e7d5ad..9726b6dd78f63980d9916f3b18a5b66c48c7b36c 100644 (file)
@@ -109,13 +109,13 @@ HINTS: >upper string ;
     lt? [ lithuanian>upper ] when
     [ title>> ] [ ch>title ] map-case ; inline
 
-: title-word ( string -- title )
-    unclip 1string [ >lower ] [ (>title) ] bi* prepend ; inline
-
 PRIVATE>
 
+: capitalize ( string -- title )
+    unclip 1string [ >lower ] [ (>title) ] bi* prepend ; inline
+
 : >title ( string -- title )
-    final-sigma >words [ title-word ] map concat ;
+    final-sigma >words [ capitalize ] map concat ;
 
 HINTS: >title string ;
 
index 3bc81cd6816cc761d4bf3ec9b5dbe6692c061164..b618c4b608597b06d54eff76049dd3f26fad2db9 100644 (file)
@@ -56,7 +56,7 @@ M: audio-listener audio-gain gain>> ; inline
 M: audio-listener audio-velocity velocity>> ; inline
 M: audio-listener audio-orientation orientation>> ; inline
 
-GENERIC# generate-audio 1 ( generator buffer-size -- c-ptr size )
+GENERIC: generate-audio ( generator -- c-ptr size )
 GENERIC: generator-audio-format ( generator -- channels sample-bits sample-rate )
 
 TUPLE: audio-engine < disposable
@@ -79,7 +79,6 @@ TUPLE: static-audio-clip < audio-clip
 
 TUPLE: streaming-audio-clip < audio-clip
     generator
-    { buffer-size integer }
     { channels integer }
     { sample-bits integer }
     { sample-rate integer }
@@ -151,8 +150,7 @@ ERROR: audio-context-not-available device-name ;
 :: queue-clip-buffer ( audio-clip al-buffer -- )
     audio-clip al-source>> :> al-source
     audio-clip generator>> :> generator
-    audio-clip buffer-size>> :> buffer-size
-    generator buffer-size generate-audio :> ( data size )
+    generator generate-audio :> ( data size )
 
     data [
         al-buffer audio-clip openal-format data size audio-clip sample-rate>> alBufferData
@@ -267,7 +265,7 @@ M: audio-engine dispose*
         clip
     ] [ f ] if ;
 
-:: <streaming-audio-clip> ( audio-engine source generator buffer-size buffer-count -- audio-clip/f )
+:: <streaming-audio-clip> ( audio-engine source generator buffer-count -- audio-clip/f )
     audio-engine get-available-source :> al-source
 
     al-source [
@@ -279,7 +277,6 @@ M: audio-engine dispose*
             source >>source
             al-source >>al-source
             generator >>generator
-            buffer-size >>buffer-size
             channels >>channels
             sample-bits >>sample-bits
             sample-rate >>sample-rate
@@ -288,7 +285,7 @@ M: audio-engine dispose*
         al-buffers [ clip swap queue-clip-buffer ] each
         clip audio-engine clips>> push
         clip
-    ] [ f ] if ;
+    ] [ generator dispose f ] if ;
 
 M: audio-clip dispose*
     [ dup audio-engine>> clips>> remove! drop ]
@@ -300,7 +297,8 @@ M: static-audio-clip dispose*
 
 M: streaming-audio-clip dispose*
     [ call-next-method ]
-    [ al-buffers>> [ length ] keep alDeleteBuffers ] bi ;
+    [ generator>> dispose ]
+    [ al-buffers>> [ length ] keep alDeleteBuffers ] tri ;
 
 : play-clip ( audio-clip -- )
     [ update-source ]
@@ -313,7 +311,7 @@ M: streaming-audio-clip dispose*
 : play-static-audio-clip ( audio-engine source audio loop? -- audio-clip/f )
     <static-audio-clip> dup [ play-clip ] when* ;
 
-: play-streaming-audio-clip ( audio-engine source generator buffer-size buffer-count -- audio-clip/f ) 
+: play-streaming-audio-clip ( audio-engine source generator buffer-count -- audio-clip/f ) 
     <streaming-audio-clip> dup [ play-clip ] when* ;
 
 : pause-clip ( audio-clip -- )
index 46c45f84b1fe10e63dc70309079ca7c6cde204d4..bbc6c339e9f6b5359735d83d3fb256a676d9bb3a 100644 (file)
@@ -11,18 +11,22 @@ TUPLE: noise-generator ;
 M: noise-generator generator-audio-format
     drop 1 16 8000 ;
 M: noise-generator generate-audio
-    nip [ -1 shift [ -4096 4096 [a,b] random ] short-array{ } replicate-as ] keep ;
+    drop
+    4096 [ -4096 4096 [a,b] random ] short-array{ } replicate-as
+    8192 ;
+M: noise-generator dispose
+    drop ;
 
 :: audio-engine-test ( -- )
     "vocab:audio/engine/test/loop.aiff" read-audio :> loop-sound
     "vocab:audio/engine/test/once.wav" read-audio :> once-sound
     0 :> i!
-    <standard-audio-engine> :> engine
+    f 4 <audio-engine> :> engine
     engine start-audio*
 
     engine T{ audio-source f {  1.0 0.0 0.0 } 1.0 { 0.0 0.0 0.0 } f } loop-sound t
         play-static-audio-clip :> loop-clip
-    engine T{ audio-source f { -1.0 0.0 0.0 } 1.0 { 0.0 0.0 0.0 } f } noise-generator new 8192 2
+    engine T{ audio-source f { -1.0 0.0 0.0 } 1.0 { 0.0 0.0 0.0 } f } noise-generator new 2
         play-streaming-audio-clip :> noise-clip
 
     [
diff --git a/extra/audio/vorbis/vorbis.factor b/extra/audio/vorbis/vorbis.factor
new file mode 100644 (file)
index 0000000..ca712b8
--- /dev/null
@@ -0,0 +1,230 @@
+! (c)2007, 2010 Chris Double, Joe Groff bsd license
+USING: accessors alien.c-types audio.engine byte-arrays classes.struct
+combinators destructors fry gpu.buffers io io.files io.encodings.binary
+kernel libc locals make math math.order math.parser ogg ogg.vorbis
+sequences specialized-arrays specialized-vectors ;
+FROM: alien.c-types => float short void* ;
+SPECIALIZED-ARRAYS: float void* ;
+SPECIALIZED-VECTOR: short
+IN: audio.vorbis
+
+TUPLE: vorbis-stream < disposable
+    stream
+    { packet ogg-packet }
+    { sync-state ogg-sync-state }
+    { page ogg-page }
+    { stream-state ogg-stream-state }
+    { info vorbis-info }
+    { dsp-state vorbis-dsp-state }
+    { block vorbis-block }
+    { comment vorbis-comment }
+    { temp-state ogg-stream-state }
+    { #vorbis-headers integer initial: 0 }
+    { stream-eof? boolean } ;
+
+CONSTANT: stream-buffer-size 4096
+
+ERROR: ogg-error code ;
+ERROR: vorbis-error code ;
+ERROR: no-vorbis-in-ogg ;
+
+<PRIVATE
+: init-vorbis ( vorbis-stream -- )
+    [ sync-state>> ogg_sync_init drop ]
+    [ info>> vorbis_info_init ]
+    [ comment>> vorbis_comment_init ] tri ;
+
+: sync-buffer ( vorbis-stream -- buffer size )
+    sync-state>> stream-buffer-size ogg_sync_buffer
+    stream-buffer-size ; inline
+
+: read-bytes-into ( dest size stream -- len )
+    #! Read the given number of bytes from a stream
+    #! and store them in the destination byte array.
+    stream-read >byte-array dup length [ memcpy ] keep  ;
+
+: stream-into-buffer ( buffer size vorbis-stream -- len )
+    stream>> read-bytes-into ; inline
+
+: ?ogg-error ( n -- )
+    dup 0 < [ ogg-error ] [ drop ] if ; inline
+
+: confirm-buffer ( len vorbis-stream -- ? )
+    '[ _ sync-state>> swap ogg_sync_wrote ?ogg-error ] keep zero? not ; inline
+
+: buffer-data-from-stream ( vorbis-stream -- ? )
+    [ sync-buffer ] [ stream-into-buffer ] [ confirm-buffer ] tri ; inline
+
+: queue-page ( vorbis-stream -- )
+    [ stream-state>> ] [ page>> ] bi ogg_stream_pagein drop ; inline
+
+: retrieve-page ( vorbis-stream -- ? )
+    [ sync-state>> ] [ page>> ] bi ogg_sync_pageout 0 > ; inline
+
+: sync-pages ( vorbis-stream -- )
+    dup retrieve-page [ [ queue-page ] [ sync-pages ] bi ] [ drop ] if ;
+
+: standard-initial-header? ( vorbis-stream -- bool )
+    page>> ogg_page_bos zero? not ; inline
+
+: ogg-stream-init ( vorbis-stream -- state )
+    [ temp-state>> dup ]
+    [ page>> ogg_page_serialno ogg_stream_init ?ogg-error ] bi ; inline
+
+: ogg-stream-pagein ( state vorbis-stream -- )
+    page>> ogg_stream_pagein drop ; inline
+
+: ogg-stream-packetout ( state vorbis-stream -- )
+    packet>> ogg_stream_packetout drop ; inline
+
+: decode-packet ( vorbis-stream -- state )
+    [ ogg-stream-init ] keep
+    [ ogg-stream-pagein ] [ ogg-stream-packetout ] [ drop ] 2tri ; inline
+
+: vorbis-header? ( vorbis-stream -- ? )
+    [ info>> ] [ comment>> ] [ packet>> ] tri vorbis_synthesis_headerin 0 >= ; inline
+
+: is-initial-vorbis-packet? ( vorbis-stream -- ? )
+    dup #vorbis-headers>> zero? [ vorbis-header? ] [ drop f ] if ; inline
+
+: save-initial-vorbis-header ( state vorbis-stream -- )
+    [ stream-state>> swap dup byte-length memcpy ]
+    [ 1 >>#vorbis-headers drop ] bi ; inline
+
+: drop-initial-other-header ( state vorbis-stream -- )
+    swap ogg_stream_clear 2drop ; inline
+
+: process-initial-header ( vorbis-stream -- ? )
+    dup standard-initial-header? [
+        [ decode-packet ] keep
+        dup is-initial-vorbis-packet?
+        [ save-initial-vorbis-header ]
+        [ drop-initial-other-header ] if
+        t
+    ] [ drop f ] if ;
+
+: parse-initial-headers ( vorbis-stream -- )
+    dup retrieve-page
+    [ dup process-initial-header [ parse-initial-headers ] [ queue-page ] if ]
+    [ dup buffer-data-from-stream [ parse-initial-headers ] [ drop ] if ] if ;
+
+: have-required-vorbis-headers? ( vorbis-stream -- ? )
+    #vorbis-headers>> 1 2 between? not ; inline
+
+: ?vorbis-error ( code -- )
+    [ vorbis-error ] unless-zero ; inline
+
+: get-remaining-vorbis-header-packet ( player -- ? )
+    [ stream-state>> ] [ packet>> ] bi ogg_stream_packetout {
+        { [ dup 0 <   ] [ vorbis-error ] }
+        { [ dup zero? ] [ drop f ] }
+        [ drop t ]
+    } cond ;
+
+: decode-remaining-vorbis-header-packet ( vorbis-stream -- )
+    [ info>> ] [ comment>> ] [ packet>> ] tri vorbis_synthesis_headerin ?vorbis-error ;
+
+: parse-remaining-vorbis-headers ( vorbis-stream -- )
+    dup have-required-vorbis-headers? not [
+        dup get-remaining-vorbis-header-packet [
+            [ decode-remaining-vorbis-header-packet ]
+            [ [ 1 + ] change-#vorbis-headers drop ]
+            [ parse-remaining-vorbis-headers ] tri
+        ] [ drop ] if
+    ] [ drop ] if ;
+
+: parse-remaining-headers ( vorbis-stream -- )
+    dup have-required-vorbis-headers? not [
+        [ parse-remaining-vorbis-headers ]
+        [ dup retrieve-page [ queue-page ] [ buffer-data-from-stream drop ] if ]
+        [ parse-remaining-headers ] tri
+    ] [ drop ] if ;
+
+: init-vorbis-codec ( vorbis-stream -- )
+    [ [ dsp-state>> ] [ info>> ]  bi vorbis_synthesis_init drop ]
+    [ [ dsp-state>> ] [ block>> ] bi vorbis_block_init drop ] bi ;
+
+: initialize-decoder ( vorbis-stream -- )
+    dup #vorbis-headers>> zero?
+    [ no-vorbis-in-ogg ]
+    [ init-vorbis-codec ] if ;
+
+: get-pending-decoded-audio ( vorbis-stream -- pcm len )
+    dsp-state>> f <void*> [ vorbis_synthesis_pcmout ] keep *void* swap ;
+
+:: make-pcm-buffer ( vorbis-stream pcm len -- short-array )
+    vorbis-stream info>> channels>> :> #channels
+    pcm #channels <direct-void*-array> :> channel*s
+    #channels len * <short-vector> :> output
+
+    len iota [| sample |
+        #channels iota [| channel |
+            channel channel*s nth len <direct-float-array> :> samples
+            sample samples nth
+            -32767.0 * >integer -32767 32767 clamp
+            output push
+        ] each
+    ] each
+    output >short-array ; inline
+
+: read-samples ( vorbis-stream pcm len -- )
+    [ dsp-state>> ] [ drop ] [ ] tri* vorbis_synthesis_read drop ; inline
+
+: queue-audio ( vorbis-stream -- ? )
+    dup [ stream-state>> ] [ packet>> ] bi ogg_stream_packetout 0 > [
+        dup [ block>> ] [ packet>> ] bi vorbis_synthesis 0 = [
+            [ dsp-state>> ] [ block>> ] bi vorbis_synthesis_blockin drop
+        ] [ drop ] if t
+    ] [ drop f ] if ;
+
+: decode-audio ( vorbis-stream -- short-array/f length/f )
+    dup get-pending-decoded-audio dup 0 > [
+        [ make-pcm-buffer dup byte-length ] [ read-samples ] 3bi
+    ] [
+        2drop dup queue-audio [ decode-audio ] [ drop f f ] if
+    ] if ;
+PRIVATE>
+
+: <vorbis-stream> ( stream -- vorbis-stream )
+    [
+        vorbis-stream new-disposable
+            swap >>stream
+            ogg-packet malloc-struct |free >>packet
+            ogg-sync-state malloc-struct |free >>sync-state
+            ogg-page malloc-struct |free >>page
+            ogg-stream-state malloc-struct |free >>stream-state
+            vorbis-info malloc-struct |free >>info
+            vorbis-dsp-state malloc-struct |free >>dsp-state
+            vorbis-block malloc-struct |free >>block
+            vorbis-comment malloc-struct |free >>comment
+            ogg-stream-state malloc-struct |free >>temp-state
+        dup {
+            [ init-vorbis ]
+            [ parse-initial-headers ]
+            [ parse-remaining-headers ]
+            [ initialize-decoder ]
+        } cleave
+    ] with-destructors ;
+
+: read-vorbis-stream ( filename -- vorbis-stream )
+    binary <file-reader> <vorbis-stream> ; inline
+
+M: vorbis-stream dispose*
+    {
+        [ temp-state>>   [ free ] when* ]
+        [ comment>>      [ [ vorbis_comment_clear ] [ free ] bi ] when* ]
+        [ block>>        [ free ] when* ]
+        [ dsp-state>>    [ free ] when* ]
+        [ info>>         [ [ vorbis_info_clear ] [ free ] bi ] when* ]
+        [ stream-state>> [ free ] when* ]
+        [ page>>         [ free ] when* ]
+        [ sync-state>>   [ free ] when* ]
+        [ packet>>       [ free ] when* ]
+    } cleave ;
+
+M: vorbis-stream generator-audio-format
+    [ info>> channels>> ] [ drop 16 ] [ info>> rate>> ] tri ;
+M: vorbis-stream generate-audio
+    dup decode-audio
+    [ [ drop ] 2dip ]
+    [ drop [ buffer-data-from-stream drop ] [ sync-pages ] [ decode-audio ] tri ] if* ;
index 12c6801439e6e726c5e7015d8108f14fcb7d89a1..6a61e2ec4fc16d07f8808f8ba7e0a13fee45408b 100644 (file)
@@ -11,6 +11,8 @@ VARIANT: gpu-api
 
 : set-gpu-api ( -- )
     "2.0" require-gl-version
+    "3.0" { { "GL_ARB_vertex_array_object" "GL_APPLE_vertex_array_object" } }
+    require-gl-version-or-extensions
     "3.0" has-gl-version? opengl-3 opengl-2 ? gpu-api set-global ;
 
 HOOK: init-gpu-api gpu-api ( -- )
index d6b00d2d04ac803d5f0627f949a218a7f27f70b1..05f9f853f1b9076c02bcc6f847d974ec472a5800 100644 (file)
@@ -128,7 +128,7 @@ syn cluster factorWordOps       contains=factorConstant,factorAlias,factorSingle
 
 syn region factorString start=/\<"/ skip=/\\"/ end=/"/
 syn region factorTriString start=/\<"""/ skip=/\\"/ end=/"""/
-syn region factorSbuf start=/\<SBUF"\>/ skip=/\\"/ end=/"/
+syn region factorSbuf start=/\<[-a-zA-Z0-9]\+"\>/ skip=/\\"/ end=/"/
 
 syn region factorMultiString matchgroup=factorMultiStringDelims start=/\<STRING:\s\+\S\+\>/ end=/^;$/ contains=factorMultiStringContents
 syn match factorMultiStringContents /.*/ contained