Music NFT Metadata

Structural considerations for a Music NFT Standard

The current proposal places the asset/media properties at the top-level and then contains release/packaging info under a "project" object.

Music metadata has 3 core purposes:

  • presentation

  • discovery

  • identification

Current Standards Constraints:

  • Limited Artist information - making artist components into metadata object instead of just propertiesGet Property 'metadata.artist'

becomes

'metadata.artist.name'

Set Property

'metadata.artist = "Ly Trang" '

becomes

'metadata.artist.name = "Ly Trang" '

Proposal Impact

Improving metadata definition

Get Property

'metadata.duration'

becomes

'const song = metadata.track[0] song.duration'

Set Property

'metadata.duration = newDuration'

becomes

'const song = metadata.track[0] song.duration = newDuration'

Amended schema

  "version": string, // schema version
  "title": string,
  "artist": {
    "name": string
  },
  "artwork": { // project artwork may be different from track artwork
    "uri": string,
    "mimeType": string,
    "nft": { // nullable
      "chainId": string,
      "contractAddress": string,
      "tokenId": number,
      "externalUrl": string,
    }
  },
  "genre": string, // nullable - added
  "tags": [string], // nullable - added
  "notes": string, // nullable
  "numTracks": number,
  "type": string, // eg: ep, album, compilation
  "originalReleaseDate": DateTime ISO8601, // (or sumn) - nullable
  "recordLabel": string, // nullable
  "publisher": string, // nullable
  "compilation": boolean, // this boolean matches ID3 tags but is redundant (very open to removing)
  "links": [string], // nullable - undecided on this one
  "tracks": [ {
    "title": string,
    "artist": {
      "name": string
    },
    "description": string, // nullable
    "duration": number, // seconds
    "mimeType": string,
    "trackNumber": int, // nullable - starts at 1
    "artwork": {
        "uri": string,
        "mimeType": string,
        "nft": {...} // nullable
    },
    "visualizer": { // nullable
        "uri": string,
        "mimeType": string,
        "nft": {...} // nullable
    },
    "genre": string, // nullable
    "tags": [string], // nullable
    "lyrics": string, // nullable - could be their own NFT
    "bpm": number, // nullable
    "key": string, // nullable - open key notation (e.g. 6a)
    "language": string, // nullable
    "license": string,
    "isrc": string, // nullable
    "locationCreated": string, // nullable
    "recordedAt": string, // nullable
    "originalReleaseDate": DateTime ISO8601, // nullable - open to a different standard
    "recordLabel": string, // nullable
    "explicit": boolean, // nullable
    "credits": [ // nullable
      {
        "name": string, // e.g. Daddy Kev
        "collaboratorType": string, // e.g. composer, songwriter, performer, producer, mixingEngineer, masteringEngineer
      }
    ],
    "links": [string], // nullable
    "lossyAudio": string, // nullable - possibly redundant w/ animation_url
    "isInstrumental": boolean,
    // proposed by Foundation 👇
    "thumbnail": string,        
    },
  } ],
  // OpenSea standards 👇
  "image": string,
  "name": string,
  "external_url": string,
  "animation_url": string, // if this is lossless audio, should we include a mimeType?
  "attributes": {
    "artist" : string,
    "project": string, // nullable
    "??bpm" : number, // nullable
    "??key": string, // nullable
    "genre": string, // nullable
    "recordLabel": string, // nullable
  }
//  "losslessAudio": "<uri>", // redundant w/ contentURI & potentially animation_url
//  "samples": [],
//  "software": [],
//  "instruments": [],
//   "isRemix": false,
//  "originalSong": "", // for remixes
//  "additionalMedia": [], // how does this compete w/ visualizer?
//  "livePerformance": {
//     venue, date, etc
//  }
}

Current schema

  "version": string, // schema version
  "title": string,
  "artist": string,
  "description": string, // nullable
  "duration": number, // seconds
  "mimeType": string,
  "trackNumber": int, // nullable - starts at 1
  "project": { // nullable
      "title": string,
      "artwork": { // project artwork may be different from single artwork
         "uri": string,
         "mimeType": string,
         "nft": { // nullable
             "chainId": string,
            "contractAddress": string,
            "tokenId": number,
             "externalUrl": string,
         }
      },
      "notes": string, // nullable
      "numTracks": number,
      "type": string, // eg: ep, album, compilation
      "originalReleaseDate": DateTime ISO8601, // (or sumn) - nullable
      "recordLabel": string, // nullable
      "publisher": string, // nullable
      "compilation": boolean // this boolean matches ID3 tags but is redundant (very open to removing)
      "links": [string] // nullable - undecided on this one
  },
  "artwork": {
      "uri": string,
      "mimeType": string,
      "nft": {...} // nullable
  },
  "visualizer": { // nullable
      "uri": string,
      "mimeType": string,
      "nft": {...} // nullable
  },
  "genre": string, // nullable
  "tags": [string], // nullable
  "lyrics": string, // nullable - could be their own NFT
  "bpm": number, // nullable
  "key": string, // nullable - open key notation (e.g. 6a)
  "language": string, // nullable
  "license": string,
  "isrc": string, // nullable
  "locationCreated": string, // nullable
  "recordedAt": string, // nullable
  "originalReleaseDate": DateTime ISO8601, // nullable - open to a different standard
  "recordLabel": string, // nullable
  "explicit": boolean, // nullable
  "credits": [ // nullable
      {
        "name": string, // e.g. Daddy Kev
        "collaboratorType": string, // e.g. composer, songwriter, performer, producer, mixingEngineer, masteringEngineer
      }
  ],
  "links": [string], // nullable
  "lossyAudio": string, // nullable - possibly redundant w/ animation_url
  "isInstrumental": boolean,
  // proposed by Foundation 👇
  "thumbnail": string,
  // OpenSea standards 👇
  "image": string,
  "name": string,
  "external_url": string,
  "animation_url": string, // if this is lossless audio, should we include a mimeType?
  "attributes": {
   "artist" : string,
   "project": string, // nullable
   "bpm" : number, // nullable
   "key": string, // nullable
   "genre": string, // nullable
   "recordLabel": string, // nullable
  }
//  "losslessAudio": "<uri>", // redundant w/ contentURI & potentially animation_url
//  "samples": [],
//  "software": [],
//  "instruments": [],
//   "isRemix": false,
//  "originalSong": "", // for remixes
//  "additionalMedia": [], // how does this compete w/ visualizer?
//  "livePerformance": {
//     venue, date, etc
//  }
}

Challenges of Supporting Multiple Tracks:

  • Option 1 - Offer Single Track NFT Releases Only

  • Option 2 - Offer Single Track NFT Releases with a non NFT Multiple Track Bundle Option (which bundles the single track NFTs)

  • Option 3 - Offer Single Track NFT Releases + a Multiple Tracks NFT Release Option

More defined here: https://github.com/morestatic/musicmetadata/wiki/Music-NFT-Metadata#challenges-of-supporting-multiple-tracks Source: https://github.com/morestatic/musicmetadata/wiki/Music-NFT-Metadata Music NFT Metadata proposal: https://www.notion.so/Music-NFT-Metadata-Proposal-98871dbe2d934890a36322c638b7b6cc