github.com/boki/go-xmp@v1.0.1/models/id3/types.go (about)

     1  // Copyright (c) 2017-2018 Alexander Eichhorn
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  // http://id3.org/
    16  // http://id3.org/id3v2.4.0-frames
    17  
    18  // FIXME: Version 2.4 of the specification prescribes that all text fields
    19  // (the fields that start with a T, except for TXXX) can contain multiple
    20  // values separated by a null character. The null character varies by
    21  // character encoding.
    22  
    23  package id3
    24  
    25  import (
    26  	"bytes"
    27  	"fmt"
    28  	"strconv"
    29  	"strings"
    30  	"time"
    31  
    32  	"trimmer.io/go-xmp/models/xmp_dm"
    33  	"trimmer.io/go-xmp/xmp"
    34  )
    35  
    36  const (
    37  	TIME_FORMAT_23 = "1504" // HHMM
    38  	DATE_FORMAT_23 = "0102" // DDMM
    39  )
    40  
    41  type Bool int // 0 no, 1 yes
    42  
    43  const (
    44  	False Bool = 0
    45  	True  Bool = 1
    46  )
    47  
    48  func (b Bool) Value() bool {
    49  	return b == 1
    50  }
    51  
    52  type Time23 time.Time
    53  
    54  func (x Time23) Value() time.Time {
    55  	return time.Time(x)
    56  }
    57  
    58  func (x Time23) IsZero() bool {
    59  	return time.Time(x).IsZero()
    60  }
    61  
    62  func (x *Time23) UnmarshalText(data []byte) error {
    63  	value := string(data)
    64  	if t, err := time.Parse(TIME_FORMAT_23, value); err != nil {
    65  		return fmt.Errorf("id3: invalid time value '%s'", value)
    66  	} else {
    67  		*x = Time23(t)
    68  	}
    69  	return nil
    70  }
    71  
    72  func (x Time23) MarshalText() ([]byte, error) {
    73  	if x.IsZero() {
    74  		return nil, nil
    75  	}
    76  	return []byte(time.Time(x).Format(TIME_FORMAT_23)), nil
    77  }
    78  
    79  type Date23 time.Time
    80  
    81  func (x Date23) Value() time.Time {
    82  	return time.Time(x)
    83  }
    84  
    85  func (x Date23) IsZero() bool {
    86  	return time.Time(x).IsZero()
    87  }
    88  
    89  func (x *Date23) UnmarshalText(data []byte) error {
    90  	value := string(data)
    91  	if t, err := time.Parse(DATE_FORMAT_23, value); err != nil {
    92  		return fmt.Errorf("id3: invalid date value '%s'", value)
    93  	} else {
    94  		*x = Date23(t)
    95  	}
    96  	return nil
    97  }
    98  
    99  func (x Date23) MarshalText() ([]byte, error) {
   100  	if x.IsZero() {
   101  		return nil, nil
   102  	}
   103  	return []byte(time.Time(x).Format(DATE_FORMAT_23)), nil
   104  }
   105  
   106  // TCON
   107  //
   108  type GenreV1 byte
   109  
   110  func (x *GenreV1) UnmarshalText(data []byte) error {
   111  	value := string(data)
   112  	g, err := ParseGenreV1(value)
   113  	if err != nil {
   114  		return err
   115  	}
   116  	*x = g
   117  	return nil
   118  }
   119  
   120  func (x GenreV1) MarshalText() ([]byte, error) {
   121  	return []byte(x.String()), nil
   122  }
   123  
   124  // See Genre List at http://id3.org/id3v2.3.0
   125  func (x GenreV1) String() string {
   126  	if v, ok := GenreMap[x]; ok {
   127  		return v
   128  	}
   129  	return strconv.Itoa(int(x))
   130  }
   131  
   132  func ParseGenreV1(s string) (GenreV1, error) {
   133  	for i, v := range GenreMap {
   134  		if v == s {
   135  			return i, nil
   136  		}
   137  	}
   138  	if t, err := strconv.Atoi(s); err == nil {
   139  		return GenreV1(t), nil
   140  	}
   141  	return 0xff, fmt.Errorf("id3: invalid genre '%s'", s)
   142  }
   143  
   144  type Genre []string
   145  
   146  func (x *Genre) UnmarshalText(data []byte) error {
   147  	value := string(data)
   148  	for _, v := range strings.Split(value, ",") {
   149  		v = strings.TrimSpace(v)
   150  		if g, err := ParseGenreV1(v); err == nil {
   151  			*x = append(*x, g.String())
   152  			continue
   153  		}
   154  		switch value {
   155  		case "RX":
   156  			*x = append(*x, "Remix")
   157  		case "CR":
   158  			*x = append(*x, "Cover")
   159  		default:
   160  			*x = append(*x, value)
   161  		}
   162  	}
   163  	return nil
   164  }
   165  
   166  func (x Genre) String() string {
   167  	return strings.Join(x, ", ")
   168  }
   169  
   170  func (x Genre) MarshalText() ([]byte, error) {
   171  	return []byte(x.String()), nil
   172  }
   173  
   174  // TRCK
   175  // 10
   176  // 10/12
   177  type TrackNum struct {
   178  	Track int
   179  	Total int
   180  }
   181  
   182  func (x TrackNum) Value() int {
   183  	return x.Track
   184  }
   185  
   186  func (x TrackNum) IsZero() bool {
   187  	return x.Track == 0 && x.Total == 0
   188  }
   189  
   190  func (x *TrackNum) UnmarshalText(data []byte) error {
   191  	var err error
   192  	v := string(data)
   193  	n := TrackNum{}
   194  	if strings.Contains(v, "/") {
   195  		_, err = fmt.Sscanf(v, "%d/%d", &n.Track, &n.Total)
   196  	} else {
   197  		n.Track, err = strconv.Atoi(v)
   198  	}
   199  	if err != nil {
   200  		return fmt.Errorf("id3: invalid track number '%s': %v", v, err)
   201  	}
   202  	*x = n
   203  	return nil
   204  }
   205  
   206  func (x TrackNum) MarshalText() ([]byte, error) {
   207  	if x.Total == 0 {
   208  		return []byte(strconv.Itoa(x.Track)), nil
   209  	}
   210  	buf := bytes.Buffer{}
   211  	buf.WriteString(strconv.FormatInt(int64(x.Track), 10))
   212  	buf.WriteByte('/')
   213  	buf.WriteString(strconv.FormatInt(int64(x.Total), 10))
   214  	return buf.Bytes(), nil
   215  }
   216  
   217  // OWNE
   218  type Owner struct {
   219  	Currency     string   `xmp:"id3:currency"`
   220  	Price        float32  `xmp:"id3:price"`
   221  	PurchaseDate xmp.Date `xmp:"id3:purchaseDate"`
   222  	Seller       string   `xmp:"id3:seller"`
   223  }
   224  
   225  func (x *Owner) UnmarshalText(data []byte) error {
   226  	// TODO: need samples
   227  	return nil
   228  }
   229  
   230  // ETCO
   231  type Marker struct {
   232  	MarkerType MarkerType `xmp:"id3:type,attr"`
   233  	Timestamp  int64      `xmp:"id3:timestamp,attr"`
   234  	Unit       UnitType   `xmp:"id3:unit,attr"`
   235  }
   236  
   237  type MarkerList []Marker
   238  
   239  func (x *MarkerList) UnmarshalText(data []byte) error {
   240  	// TODO: need samples
   241  	return nil
   242  }
   243  
   244  func (x MarkerList) Typ() xmp.ArrayType {
   245  	return xmp.ArrayTypeOrdered
   246  }
   247  
   248  func (x MarkerList) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   249  	return xmp.MarshalArray(e, node, x.Typ(), x)
   250  }
   251  
   252  func (x *MarkerList) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   253  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   254  }
   255  
   256  // SYLT
   257  //
   258  type TimedLyrics struct {
   259  	Lang   string        `xmp:"id3:lang,attr"`
   260  	Type   LyricsType    `xmp:"id3:type,attr"`
   261  	Unit   PositionType  `xmp:"id3:unit,attr"`
   262  	Lyrics TimedTextList `xmp:"id3:lyrics,attr"`
   263  }
   264  
   265  type TimedLyricsArray []TimedLyrics
   266  
   267  func (x TimedLyricsArray) Typ() xmp.ArrayType {
   268  	return xmp.ArrayTypeUnordered
   269  }
   270  
   271  func (x TimedLyricsArray) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   272  	return xmp.MarshalArray(e, node, x.Typ(), x)
   273  }
   274  
   275  func (x *TimedLyricsArray) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   276  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   277  }
   278  
   279  // see id3 v.24 spec 4.9
   280  // - one id3 frame per language and content type
   281  // - null-terminated text followed by a timestamp and optionally newline
   282  //
   283  //    "Strang" $00 xx xx "ers" $00 xx xx " in" $00 xx xx " the" $00 xx xx
   284  //    " night" $00 xx xx 0A "Ex" $00 xx xx "chang" $00 xx xx "ing" $00 xx
   285  //    xx "glan" $00 xx xx "ces" $00 xx xx
   286  //
   287  func (x *TimedLyricsArray) UnmarshalText(data []byte) error {
   288  	// TODO: need samples
   289  	return nil
   290  }
   291  
   292  type TimedText struct {
   293  	Text      string `xmp:"id3:text,attr"`
   294  	Timestamp int64  `xmp:"id3:timestamp,attr"`
   295  }
   296  
   297  type TimedTextList []TimedText
   298  
   299  func (x TimedTextList) Typ() xmp.ArrayType {
   300  	return xmp.ArrayTypeOrdered
   301  }
   302  
   303  func (x TimedTextList) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   304  	return xmp.MarshalArray(e, node, x.Typ(), x)
   305  }
   306  
   307  func (x *TimedTextList) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   308  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   309  }
   310  
   311  // COMM
   312  //
   313  type Comment struct {
   314  	Lang string `xmp:"id3:lang,attr"`
   315  	Type string `xmp:"id3:type,attr"`
   316  	Text string `xmp:"id3:text,attr"`
   317  }
   318  
   319  type CommentArray []Comment
   320  
   321  // TODO: need samples
   322  func (x *CommentArray) UnmarshalText(data []byte) error {
   323  	*x = append(*x, Comment{
   324  		Text: string(data),
   325  	})
   326  	return nil
   327  }
   328  
   329  func (x CommentArray) Typ() xmp.ArrayType {
   330  	return xmp.ArrayTypeUnordered
   331  }
   332  
   333  func (x CommentArray) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   334  	return xmp.MarshalArray(e, node, x.Typ(), x)
   335  }
   336  
   337  func (x *CommentArray) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   338  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   339  }
   340  
   341  // RVA2
   342  //
   343  type VolumeAdjust struct {
   344  	Channel    ChannelType `xmp:"id3:channel,attr"`
   345  	Adjustment float32     `xmp:"id3:adjust,attr"`
   346  	Bits       byte        `xmp:"id3:bits,attr"`
   347  	PeakVolume float32     `xmp:"id3:peak,attr"`
   348  }
   349  
   350  type VolumeAdjustArray []VolumeAdjust
   351  
   352  func (x *VolumeAdjustArray) UnmarshalText(data []byte) error {
   353  	// TODO: need samples
   354  	return nil
   355  }
   356  
   357  func (x VolumeAdjustArray) Typ() xmp.ArrayType {
   358  	return xmp.ArrayTypeUnordered
   359  }
   360  
   361  func (x VolumeAdjustArray) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   362  	return xmp.MarshalArray(e, node, x.Typ(), x)
   363  }
   364  
   365  func (x *VolumeAdjustArray) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   366  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   367  }
   368  
   369  // EQU2
   370  //
   371  type Equalization struct {
   372  	Method         EqualizationMethod  `xmp:"id3:method,attr"`
   373  	Identification string              `xmp:"id3:id,attr"`
   374  	Adjustments    AdjustmentPointList `xmp:"id3:points"`
   375  }
   376  
   377  type EqualizationList []Equalization
   378  
   379  func (x *EqualizationList) UnmarshalText(data []byte) error {
   380  	// TODO: need samples
   381  	return nil
   382  }
   383  
   384  func (x EqualizationList) Typ() xmp.ArrayType {
   385  	return xmp.ArrayTypeUnordered
   386  }
   387  
   388  func (x EqualizationList) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   389  	return xmp.MarshalArray(e, node, x.Typ(), x)
   390  }
   391  
   392  func (x *EqualizationList) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   393  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   394  }
   395  
   396  type AdjustmentPoint struct {
   397  	Frequency  int     `xmp:"id3:frequency,attr"`
   398  	Adjustment float32 `xmp:"id3:adjust,attr"`
   399  }
   400  
   401  type AdjustmentPointList []AdjustmentPoint
   402  
   403  func (x AdjustmentPointList) Typ() xmp.ArrayType {
   404  	return xmp.ArrayTypeOrdered
   405  }
   406  
   407  func (x AdjustmentPointList) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   408  	return xmp.MarshalArray(e, node, x.Typ(), x)
   409  }
   410  
   411  func (x *AdjustmentPointList) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   412  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   413  }
   414  
   415  // RVRB
   416  type Reverb struct {
   417  	ReverbLeftMs       int  `xmp:"id3:reverbLeftMs"`
   418  	ReverbRightMs      int  `xmp:"id3:reverbRightMs"`
   419  	ReverbBouncesLeft  byte `xmp:"id3:reverbBouncesLeft"`
   420  	ReverbBouncesRight byte `xmp:"id3:reverbBouncesRight"`
   421  	ReverbFeedbackLtoL byte `xmp:"id3:reverbFeedbackLtoL"`
   422  	ReverbFeedbackLToR byte `xmp:"id3:reverbFeedbackLToR"`
   423  	ReverbFeedbackRtoR byte `xmp:"id3:reverbFeedbackRtoR"`
   424  	ReverbFeedbackRtoL byte `xmp:"id3:reverbFeedbackRtoL"`
   425  	PremixLtoR         byte `xmp:"id3:premixLtoR"`
   426  	PremixRtoL         byte `xmp:"id3:premixRtoL"`
   427  }
   428  
   429  func (x *Reverb) UnmarshalText(data []byte) error {
   430  	// TODO: need samples
   431  	return nil
   432  }
   433  
   434  // APIC
   435  //
   436  type AttachedPicture struct {
   437  	Mimetype    string      `xmp:"id3:mimetype,attr"`
   438  	Type        PictureType `xmp:"id3:pictureType,attr"`
   439  	Description string      `xmp:"id3:description,attr"`
   440  	Data        []byte      `xmp:"id3:image"`
   441  }
   442  
   443  type AttachedPictureArray []AttachedPicture
   444  
   445  func (x *AttachedPictureArray) UnmarshalText(data []byte) error {
   446  	// TODO: need samples
   447  	return nil
   448  }
   449  
   450  func (x AttachedPictureArray) Typ() xmp.ArrayType {
   451  	return xmp.ArrayTypeUnordered
   452  }
   453  
   454  func (x AttachedPictureArray) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   455  	return xmp.MarshalArray(e, node, x.Typ(), x)
   456  }
   457  
   458  func (x *AttachedPictureArray) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   459  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   460  }
   461  
   462  // GEOB
   463  //
   464  type EncapsulatedObject struct {
   465  	Mimetype    string `xmp:"id3:mimetype,attr"`
   466  	Filename    string `xmp:"id3:filename,attr"`
   467  	Description string `xmp:"id3:description,attr"`
   468  	Data        []byte `xmp:"id3:data"`
   469  }
   470  
   471  type EncapsulatedObjectArray []EncapsulatedObject
   472  
   473  func (x *EncapsulatedObjectArray) UnmarshalText(data []byte) error {
   474  	// TODO: need samples
   475  	return nil
   476  }
   477  
   478  func (x EncapsulatedObjectArray) Typ() xmp.ArrayType {
   479  	return xmp.ArrayTypeUnordered
   480  }
   481  
   482  func (x EncapsulatedObjectArray) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   483  	return xmp.MarshalArray(e, node, x.Typ(), x)
   484  }
   485  
   486  func (x *EncapsulatedObjectArray) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   487  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   488  }
   489  
   490  // POPM
   491  //
   492  type Popularimeter struct {
   493  	Email   string `xmp:"id3:email,attr"`
   494  	Rating  byte   `xmp:"id3:rating,attr"`
   495  	Counter int64  `xmp:"id3:counter,attr"`
   496  }
   497  
   498  type PopularimeterArray []Popularimeter
   499  
   500  func (x *PopularimeterArray) UnmarshalText(data []byte) error {
   501  	// TODO: need samples
   502  	return nil
   503  }
   504  
   505  func (x PopularimeterArray) Typ() xmp.ArrayType {
   506  	return xmp.ArrayTypeUnordered
   507  }
   508  
   509  func (x PopularimeterArray) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   510  	return xmp.MarshalArray(e, node, x.Typ(), x)
   511  }
   512  
   513  func (x *PopularimeterArray) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   514  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   515  }
   516  
   517  // RBUF
   518  //
   519  type BufferSize struct {
   520  	BufferSize int64 `xmp:"id3:bufferSize,attr"`
   521  	Flag       byte  `xmp:"id3:flag,attr"`
   522  	NextOffset int64 `xmp:"id3:next,attr"`
   523  }
   524  
   525  func (x *BufferSize) UnmarshalText(data []byte) error {
   526  	// TODO: need samples
   527  	return nil
   528  }
   529  
   530  // AENC
   531  //
   532  type AudioEncryption struct {
   533  	Owner          string `xmp:"id3:owner,attr"`
   534  	PreviewStart   int    `xmp:"id3:previewStart,attr"`
   535  	PreviewLength  int    `xmp:"id3:previewLength,attr"`
   536  	EncryptionInfo []byte `xmp:"id3:encryptionInfo"`
   537  }
   538  
   539  func (x *AudioEncryption) UnmarshalText(data []byte) error {
   540  	// TODO: need samples
   541  	return nil
   542  }
   543  
   544  // LINK
   545  //
   546  type Link struct {
   547  	LinkedID string         `xmp:"id3:linkedId,attr"`
   548  	Url      string         `xmp:"id3:url,attr"`
   549  	Extra    xmp.StringList `xmp:"id3:extra"`
   550  }
   551  
   552  type LinkArray []Link
   553  
   554  func (x *LinkArray) UnmarshalText(data []byte) error {
   555  	// TODO: need samples
   556  	return nil
   557  }
   558  
   559  func (x LinkArray) Typ() xmp.ArrayType {
   560  	return xmp.ArrayTypeUnordered
   561  }
   562  
   563  func (x LinkArray) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   564  	return xmp.MarshalArray(e, node, x.Typ(), x)
   565  }
   566  
   567  func (x *LinkArray) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   568  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   569  }
   570  
   571  // POSS
   572  //
   573  type PositionSync struct {
   574  	Unit     PositionType `xmp:"id3:unit,attr"`
   575  	Position int64        `xmp:"id3:position,attr"`
   576  }
   577  
   578  // COMR
   579  //
   580  type Commercial struct {
   581  	Prices       PriceList      `xmp:"id3:prices"`
   582  	ValidUntil   Date23         `xmp:"id3:validUntil,attr"`
   583  	ContactUrl   xmp.Url        `xmp:"id3:contactUrl"`
   584  	ReceivedAs   DeliveryMethod `xmp:"id3:receivedAs,attr"`
   585  	SellerName   string         `xmp:"id3:sellerName,attr"`
   586  	Description  string         `xmp:"id3:description,attr"`
   587  	LogoMimetype string         `xmp:"id3:logoMimetype,attr"`
   588  	LogoImage    []byte         `xmp:"id3:logoImage"`
   589  }
   590  
   591  func (x *Commercial) UnmarshalText(data []byte) error {
   592  	// TODO: need samples
   593  	return nil
   594  }
   595  
   596  type Price struct {
   597  	Currency string
   598  	Amount   float32
   599  }
   600  
   601  type PriceList []Price
   602  
   603  func (x PriceList) Typ() xmp.ArrayType {
   604  	return xmp.ArrayTypeUnordered
   605  }
   606  
   607  func (x PriceList) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   608  	return xmp.MarshalArray(e, node, x.Typ(), x)
   609  }
   610  
   611  func (x *PriceList) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   612  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   613  }
   614  
   615  // ENCR
   616  //
   617  type EncryptionMethod struct {
   618  	OwnerUrl xmp.Url `xmp:"id3:ownerUrl,attr"`
   619  	Method   byte    `xmp:"id3:method,attr"`
   620  	Data     []byte  `xmp:"id3:data"`
   621  }
   622  
   623  type EncryptionMethodArray []EncryptionMethod
   624  
   625  func (x *EncryptionMethodArray) UnmarshalText(data []byte) error {
   626  	// TODO: need samples
   627  	return nil
   628  }
   629  
   630  func (x EncryptionMethodArray) Typ() xmp.ArrayType {
   631  	return xmp.ArrayTypeUnordered
   632  }
   633  
   634  func (x EncryptionMethodArray) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   635  	return xmp.MarshalArray(e, node, x.Typ(), x)
   636  }
   637  
   638  func (x *EncryptionMethodArray) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   639  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   640  }
   641  
   642  // GRID
   643  //
   644  type Group struct {
   645  	OwnerUrl xmp.Url `xmp:"id3:ownerUrl,attr"`
   646  	Symbol   byte    `xmp:"id3:symbol,attr"` // 0x80-0xF0
   647  	Data     []byte  `xmp:"id3:data"`
   648  }
   649  
   650  type GroupArray []Group
   651  
   652  func (x *GroupArray) UnmarshalText(data []byte) error {
   653  	// TODO: need samples
   654  	return nil
   655  }
   656  
   657  func (x GroupArray) Typ() xmp.ArrayType {
   658  	return xmp.ArrayTypeUnordered
   659  }
   660  
   661  func (x GroupArray) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   662  	return xmp.MarshalArray(e, node, x.Typ(), x)
   663  }
   664  
   665  func (x *GroupArray) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   666  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   667  }
   668  
   669  // PRIV
   670  //
   671  type PrivateData struct {
   672  	Owner string `xmp:"id3:owner,attr"`
   673  	Data  []byte `xmp:"id3:data"`
   674  }
   675  
   676  type PrivateDataArray []PrivateData
   677  
   678  func (x *PrivateDataArray) UnmarshalText(data []byte) error {
   679  	// TODO: need samples
   680  	return nil
   681  }
   682  
   683  func (x PrivateDataArray) Typ() xmp.ArrayType {
   684  	return xmp.ArrayTypeUnordered
   685  }
   686  
   687  func (x PrivateDataArray) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   688  	return xmp.MarshalArray(e, node, x.Typ(), x)
   689  }
   690  
   691  func (x *PrivateDataArray) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   692  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   693  }
   694  
   695  // SIGN
   696  //
   697  type Signature struct {
   698  	GroupSymbol byte   `xmp:"id3:groupSymbol,attr"` // 0x80-0xF0
   699  	Signature   []byte `xmp:"id3:signature"`
   700  }
   701  
   702  type SignatureArray []Signature
   703  
   704  func (x *SignatureArray) UnmarshalText(data []byte) error {
   705  	// TODO: need samples
   706  	return nil
   707  }
   708  
   709  func (x SignatureArray) Typ() xmp.ArrayType {
   710  	return xmp.ArrayTypeUnordered
   711  }
   712  
   713  func (x SignatureArray) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   714  	return xmp.MarshalArray(e, node, x.Typ(), x)
   715  }
   716  
   717  func (x *SignatureArray) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   718  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   719  }
   720  
   721  // ASPI
   722  //
   723  type AudioSeekIndex struct {
   724  	Start          int64       `xmp:"id3:start,attr"`
   725  	Length         int64       `xmp:"id3:length,attr"`
   726  	NumberOfPoints int         `xmp:"id3:numberOfPoints,attr"`
   727  	BitsPerPoint   byte        `xmp:"id3:bitsPerPoint,attr"`
   728  	Points         xmp.IntList `xmp:"id3:points"`
   729  }
   730  
   731  func (x *AudioSeekIndex) UnmarshalText(data []byte) error {
   732  	// TODO: need samples
   733  	return nil
   734  }
   735  
   736  // CHAP
   737  //
   738  type Chapter xmpdm.Marker
   739  
   740  type ChapterList []Chapter
   741  
   742  func (x *ChapterList) UnmarshalText(data []byte) error {
   743  	// TODO: need samples
   744  	return nil
   745  }
   746  
   747  func (x ChapterList) Typ() xmp.ArrayType {
   748  	return xmp.ArrayTypeOrdered
   749  }
   750  
   751  func (x ChapterList) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   752  	return xmp.MarshalArray(e, node, x.Typ(), x)
   753  }
   754  
   755  func (x *ChapterList) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   756  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   757  }
   758  
   759  // CTOC
   760  //
   761  type TocEntry struct {
   762  	Flags  int            `xmp:"id3:flags"`
   763  	IDList xmp.StringList `xmp:"id3:idlist"`
   764  	Info   string         `xmp:"id3:info"`
   765  }
   766  
   767  type TocEntryList []TocEntry
   768  
   769  func (x *TocEntryList) UnmarshalText(data []byte) error {
   770  	// TODO: need samples
   771  	return nil
   772  }
   773  
   774  func (x TocEntryList) Typ() xmp.ArrayType {
   775  	return xmp.ArrayTypeOrdered
   776  }
   777  
   778  func (x TocEntryList) MarshalXMP(e *xmp.Encoder, node *xmp.Node, m xmp.Model) error {
   779  	return xmp.MarshalArray(e, node, x.Typ(), x)
   780  }
   781  
   782  func (x *TocEntryList) UnmarshalXMP(d *xmp.Decoder, node *xmp.Node, m xmp.Model) error {
   783  	return xmp.UnmarshalArray(d, node, x.Typ(), x)
   784  }