{"id":55295,"date":"2026-05-21T10:58:14","date_gmt":"2026-05-21T17:58:14","guid":{"rendered":"https:\/\/www.griddb.net\/?p=55295"},"modified":"2026-05-28T11:07:14","modified_gmt":"2026-05-28T18:07:14","slug":"create-dynamic-ambient-music-using-ai-and-iot-data","status":"publish","type":"post","link":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/","title":{"rendered":"Create Dynamic Ambient Music Using AI and IoT Data"},"content":{"rendered":"<p>\nThis tutorial shows how to generate evolving ambient music driven by IoT sensor data. We\u2019ll ingest sensor readings into <strong>GridDB<\/strong> database, map those readings to musical parameters using OpenAI, and call <strong>ElevenLabs Music<\/strong> to render an audio track. The UI is built with <strong>React + Vite<\/strong>, and the backend is <strong>Node.js<\/strong>.\n<\/p>\n<h2 id=\"introduction\">Introduction<\/h2>\n<p>\nAmbient music thrives on context. Here, the environment literally composes the score. Heat can slow the tempo, humidity can soften the timbre, and human presence can thicken the arrangement. We\u2019ll stitch together a small system: devices post telemetry (we will use the data directly), GridDB keeps the data, the AI model creates music parameters, and ElevenLabs will render audio that you can play instantly in the browser.\n<\/p>\n<h2 id=\"system-architecture\">System Architecture<\/h2>\n<p><a href=\"\/wp-content\/uploads\/2026\/05\/griddb-elevenlabs-ambient-music-scaled.png\"><img fetchpriority=\"high\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/griddb-elevenlabs-ambient-music-scaled.png\" alt=\"\" width=\"2560\" height=\"859\" class=\"aligncenter size-full wp-image-55298\" srcset=\"\/wp-content\/uploads\/2026\/05\/griddb-elevenlabs-ambient-music-scaled.png 2560w, \/wp-content\/uploads\/2026\/05\/griddb-elevenlabs-ambient-music-300x101.png 300w, \/wp-content\/uploads\/2026\/05\/griddb-elevenlabs-ambient-music-1024x343.png 1024w, \/wp-content\/uploads\/2026\/05\/griddb-elevenlabs-ambient-music-768x258.png 768w, \/wp-content\/uploads\/2026\/05\/griddb-elevenlabs-ambient-music-1536x515.png 1536w, \/wp-content\/uploads\/2026\/05\/griddb-elevenlabs-ambient-music-2048x687.png 2048w, \/wp-content\/uploads\/2026\/05\/griddb-elevenlabs-ambient-music-600x201.png 600w\" sizes=\"(max-width: 2560px) 100vw, 2560px\" \/><\/a><\/p>\n<p>\nThe system has several core components working together to turn IoT data into ambient sound:\n<\/p>\n<p><strong>IoT Data Source<\/strong><\/p>\n<p>\nEnvironmental sensors capture values such as temperature, humidity, sound levels, and occupancy. These readings are the raw input for the music generation process.\n<\/p>\n<p><strong>Node.js Backend<\/strong><\/p>\n<p>\nNode.js acts as the central orchestrator. It receives IoT sensor readings and coordinates interactions between the AI models, the music generator, and the database.\n<\/p>\n<p><strong>OpenAI Model<\/strong><\/p>\n<p>\nThe IoT data is processed by an OpenAI model. The model transforms the data into a musical prompt. For example, \u201ccalm ambient soundscape with airy textures and slow tempo.\u201d This ensures the music reflects the current environment in a more human-like, descriptive way.\n<\/p>\n<p><strong>ElevenLabs Music API<\/strong><\/p>\n<p>\nThe generated music prompt is sent to the ElevenLabs Music API. ElevenLabs then produces an audio track that matches the description. The result is ambient audio that adapts to real-world conditions.\n<\/p>\n<p><strong>GridDB Database<\/strong><\/p>\n<p>\nBoth the music prompt and the audio metadata (such as file path or data URL) are stored in GridDB. GridDB also keeps the original IoT readings.\n<\/p>\n<p><strong>React + Vite Frontend<\/strong><\/p>\n<p>\nThe frontend provides a web-based interface where users can trigger new music generation, view sensor snapshots, and play the most recent ambient tracks.\n<\/p>\n<h2 id=\"prerequisites\">Prerequisites<\/h2>\n<h3 id=\"nodejs\">Node.js<\/h3>\n<p>\nThis project is built using React + Vite, which requires Node.js version 16 or higher. You can download and install Node.js from <a href=\"https:\/\/nodejs.org\/en\">https:\/\/nodejs.org\/en<\/a>.\n<\/p>\n<h3 id=\"openai\">OpenAI<\/h3>\n<p>\nCreate the OpenAI API key <a href=\"https:\/\/platform.openai.com\/\">here<\/a>. You may need to create a project and enable a few models.\n<\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/05\/enabled-openai-models.png\"><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/enabled-openai-models.png\" alt=\"\" width=\"985\" height=\"253\" class=\"aligncenter size-full wp-image-55303\" srcset=\"\/wp-content\/uploads\/2026\/05\/enabled-openai-models.png 985w, \/wp-content\/uploads\/2026\/05\/enabled-openai-models-300x77.png 300w, \/wp-content\/uploads\/2026\/05\/enabled-openai-models-768x197.png 768w, \/wp-content\/uploads\/2026\/05\/enabled-openai-models-600x154.png 600w\" sizes=\"(max-width: 985px) 100vw, 985px\" \/><\/a><\/p>\n<p>\nIn this project, we will use an AI model from OpenAI:\n<\/p>\n<ul>\n<li><code>gpt-5-mini<\/code> to create an audio prompt.<\/li>\n<\/ul>\n<h3 id=\"griddb\">GridDB<\/h3>\n<h4 id=\"sign-up-for-griddb-cloud-free-plan\">Sign Up for GridDB Cloud Free Plan<\/h4>\n<p>\nIf you would like to sign up for a GridDB Cloud Free instance, you can do so at the following link: <a href=\"https:\/\/form.ict-toshiba.jp\/download_form_griddb_cloud_freeplan_e\">https:\/\/form.ict-toshiba.jp\/download_form_griddb_cloud_freeplan_e<\/a>.\n<\/p>\n<p>\nAfter successfully signing up, you will receive a free instance along with the necessary details to access the GridDB Cloud Management GUI, including the <strong>GridDB Cloud Portal URL<\/strong>, <strong>Contract ID<\/strong>, <strong>Login<\/strong>, and <strong>Password<\/strong>.\n<\/p>\n<h4 id=\"griddb-webapi-url\">GridDB WebAPI URL<\/h4>\n<p>\nGo to the GridDB Cloud Portal and copy the WebAPI URL from the <strong>Clusters<\/strong> section. It should look like this:\n<\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/05\/griddb-cloud-portal-scaled.png\"><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/griddb-cloud-portal-scaled.png\" alt=\"\" width=\"2560\" height=\"1265\" class=\"aligncenter size-full wp-image-55302\" srcset=\"\/wp-content\/uploads\/2026\/05\/griddb-cloud-portal-scaled.png 2560w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-portal-300x148.png 300w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-portal-1024x506.png 1024w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-portal-768x380.png 768w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-portal-1536x759.png 1536w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-portal-2048x1012.png 2048w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-portal-600x297.png 600w\" sizes=\"(max-width: 2560px) 100vw, 2560px\" \/><\/a><\/p>\n<h4 id=\"griddb-username-and-password\">GridDB Username and Password<\/h4>\n<p>\nGo to the <strong>GridDB Users<\/strong> section of the GridDB Cloud portal and create or copy the username for <code>GRIDDB_USERNAME<\/code>. The password is set when the user is created for the first time. Use this as the <code>GRIDDB_PASSWORD<\/code>.\n<\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/05\/griddb-cloud-users-scaled.png\"><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/griddb-cloud-users-scaled.png\" alt=\"\" width=\"2560\" height=\"1351\" class=\"aligncenter size-full wp-image-55301\" srcset=\"\/wp-content\/uploads\/2026\/05\/griddb-cloud-users-scaled.png 2560w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-users-300x158.png 300w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-users-1024x540.png 1024w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-users-768x405.png 768w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-users-1536x810.png 1536w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-users-2048x1080.png 2048w, \/wp-content\/uploads\/2026\/05\/griddb-cloud-users-600x317.png 600w\" sizes=\"(max-width: 2560px) 100vw, 2560px\" \/><\/a><\/p>\n<p>\nFor more details, to get started with GridDB Cloud, please follow this <a href=\"https:\/\/griddb.net\/en\/blog\/griddb-cloud-quick-start-guide\/\">quick start guide<\/a>.\n<\/p>\n<h4 id=\"ip-whitelist\">IP Whitelist<\/h4>\n<p>\nWhen running this project, please ensure that the IP address where the project is running is whitelisted. Failure to do so will result in a 403 status code or forbidden access.\n<\/p>\n<p>\nYou can use a website like <a href=\"https:\/\/whatismyipaddress.com\/\">What Is My IP Address<\/a> to find your public IP address.\n<\/p>\n<p>\nTo whitelist the IP, go to the GridDB Cloud Admin and navigate to the <strong>Network Access<\/strong> menu.\n<\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/05\/ip-whitelist-scaled.png\"><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/ip-whitelist-scaled.png\" alt=\"\" width=\"2560\" height=\"1095\" class=\"aligncenter size-full wp-image-55297\" srcset=\"\/wp-content\/uploads\/2026\/05\/ip-whitelist-scaled.png 2560w, \/wp-content\/uploads\/2026\/05\/ip-whitelist-300x128.png 300w, \/wp-content\/uploads\/2026\/05\/ip-whitelist-1024x438.png 1024w, \/wp-content\/uploads\/2026\/05\/ip-whitelist-768x329.png 768w, \/wp-content\/uploads\/2026\/05\/ip-whitelist-1536x657.png 1536w, \/wp-content\/uploads\/2026\/05\/ip-whitelist-2048x876.png 2048w, \/wp-content\/uploads\/2026\/05\/ip-whitelist-600x257.png 600w\" sizes=\"(max-width: 2560px) 100vw, 2560px\" \/><\/a><\/p>\n<h3 id=\"elevenlabs\">ElevenLabs<\/h3>\n<p>\nYou need an ElevenLabs account and API key to use this project. You can sign up for an account at <a href=\"https:\/\/elevenlabs.io\/signup\">https:\/\/elevenlabs.io\/signup<\/a>.\n<\/p>\n<p>\nAfter signing up, go to the <a href=\"https:\/\/elevenlabs.io\/app\/developers\/api-keys\"><strong>Developer<\/strong><\/a> section, and create and copy your API key.\n<\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/05\/elevenlabs-api-key.png\"><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/elevenlabs-api-key.png\" alt=\"\" width=\"1094\" height=\"409\" class=\"aligncenter size-full wp-image-55304\" srcset=\"\/wp-content\/uploads\/2026\/05\/elevenlabs-api-key.png 1094w, \/wp-content\/uploads\/2026\/05\/elevenlabs-api-key-300x112.png 300w, \/wp-content\/uploads\/2026\/05\/elevenlabs-api-key-1024x383.png 1024w, \/wp-content\/uploads\/2026\/05\/elevenlabs-api-key-768x287.png 768w, \/wp-content\/uploads\/2026\/05\/elevenlabs-api-key-600x224.png 600w\" sizes=\"(max-width: 1094px) 100vw, 1094px\" \/><\/a><\/p>\n<p>\nAnd make sure to enable the <strong>Music Generation<\/strong> access permission.\n<\/p>\n<h2 id=\"how-to-run\">How to Run<\/h2>\n<h3 id=\"1-clone-the-repository\">1. Clone the repository<\/h3>\n<p>\nClone the repository from <a href=\"https:\/\/github.com\/junwatu\/grid-sound-ambient\">https:\/\/github.com\/junwatu\/grid-sound-ambient<\/a> to your local machine.\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">$ git clone https:\/\/github.com\/junwatu\/grid-sound-ambient.git\r\n$ cd grid-sound-ambient\r\n$ cd apps<\/code><\/pre>\n<\/div>\n<h3 id=\"2-install-dependencies\">2. Install dependencies<\/h3>\n<p>\nInstall all project dependencies using npm.\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">$ npm install<\/code><\/pre>\n<\/div>\n<h3 id=\"3-set-up-environment-variables\">3. Set up environment variables<\/h3>\n<p>\nCopy file <code>.env.example<\/code> to <code>.env<\/code> and fill in the values:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\"># Copy this file to .env.local and add your actual API keys\r\n# Never commit .env.local to version control\r\n\r\n# ElevenLabs API Key for ElevenLabs Music\r\nELEVENLABS_API_KEY=\r\n\r\nOPENAI_API_KEY=\r\n\r\nGRIDDB_WEBAPI_URL=\r\nGRIDDB_PASSWORD=\r\nGRIDDB_USERNAME=\r\n\r\nWEB_URL=http:\/\/localhost:3000<\/code><\/pre>\n<\/div>\n<p>\nPlease look at the section on <a href=\"#prerequisites\">Prerequisites<\/a> before running the project.\n<\/p>\n<h3 id=\"4-run-the-project\">4. Run the project<\/h3>\n<p>\nRun the project using the following command:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">$ npm run start<\/code><\/pre>\n<\/div>\n<h3 id=\"5-open-the-application\">5. Open the application<\/h3>\n<p>\nOpen the application in your browser at <a href=\"http:\/\/localhost:3000\">http:\/\/localhost:3000<\/a> or any address that <code>WEB_URL<\/code> is set to. You also need to allow the browser to access your microphone.\n<\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/05\/app-sc-1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/app-sc-1.png\" alt=\"\" width=\"2312\" height=\"1186\" class=\"aligncenter size-full wp-image-55308\" srcset=\"\/wp-content\/uploads\/2026\/05\/app-sc-1.png 2312w, \/wp-content\/uploads\/2026\/05\/app-sc-1-300x154.png 300w, \/wp-content\/uploads\/2026\/05\/app-sc-1-1024x525.png 1024w, \/wp-content\/uploads\/2026\/05\/app-sc-1-768x394.png 768w, \/wp-content\/uploads\/2026\/05\/app-sc-1-1536x788.png 1536w, \/wp-content\/uploads\/2026\/05\/app-sc-1-2048x1051.png 2048w, \/wp-content\/uploads\/2026\/05\/app-sc-1-600x308.png 600w\" sizes=\"(max-width: 2312px) 100vw, 2312px\" \/><\/a><\/p>\n<h2 id=\"building-the-ambient-music-generator\">Building The Ambient Music Generator<\/h2>\n<h3 id=\"iot-data\">IoT Data<\/h3>\n<p>\nIn this project, we will use pre-made IoT data. The data is an array of sensor snapshots. Each object is a single time-stamped reading for a building zone. This data mimics real data conditions from the IoT sensor.\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">[\r\n  {\r\n    &quot;timestamp&quot;: &quot;2025-08-20T09:15:00&quot;,\r\n    &quot;zone&quot;: &quot;Meeting Room A&quot;,\r\n    &quot;temperature_c&quot;: 22.8,\r\n    &quot;humidity_pct&quot;: 47,\r\n    &quot;co2_ppm&quot;: 1020,\r\n    &quot;voc_index&quot;: 185,\r\n    &quot;occupancy&quot;: 7,\r\n    &quot;noise_dba&quot;: 49,\r\n    &quot;productivity_score&quot;: 65,\r\n    &quot;trend_10min.co2_ppm_delta&quot;: 120,\r\n    &quot;trend_10min.noise_dba_delta&quot;: 1,\r\n    &quot;trend_10min.productivity_delta&quot;: -5\r\n  },\r\n  ...\r\n]<\/code><\/pre>\n<\/div>\n<p>\nYou can look at the data sample in the <code>apps\/data\/iot_music_samples.json<\/code>.\n<\/p>\n<h2 id=\"user-interface\">User Interface<\/h2>\n<p>\nThe UI is a small React app (Vite + Tailwind) that drives the end\u2011to\u2011end flow and plays generated audio.\n<\/p>\n<p>\nThe workflow for the user is:\n<\/p>\n<ol>\n<li>Click the <strong>Load example<\/strong> button to load sensor data into the text input, or you can paste a single sensor snapshot JSON into the textarea from the <code>apps\/data\/iot_music_samples.json<\/code> file.<\/li>\n<li>Click \u201cGenerate Music\u201d to call.<\/li>\n<li>The app displays the generated prompt, a brief (expandable) description, and an HTML5 audio player.<\/li>\n<li>Optionally, you can open \u201cView History\u201d to fetch recent records and replay saved tracks.<\/li>\n<\/ol>\n<p>\nThese are the server routes used by the client-side UI:\n<\/p>\n<p>\n| Method &#038; Route              | Trigger in UI                          | Purpose                                      Consumes                                                   |<br \/>\n|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br \/>\n| <code>POST<\/code> <code>\/api\/iot\/generate-music<\/code> | <strong>Generate Music<\/strong> button                 | Full pipeline: brief \u2192 prompt \u2192 music \u2192 save<br \/>\n| <code>GET<\/code>  <code>\/api\/music\/history<\/code>      | <strong>View History<\/strong> modal                    | Load saved generations<br \/>\n| <code>GET<\/code>  <code>\/audio\/<filename><\/code>       | Audio players in results\/history        | Stream ambient music from server\n<\/p>\n<p>\nThe client data returned from the server is JSON. It contains all the data needed for the UI, from music prompt, music brief, to audio metadata such as audio path and filename.\n<\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/05\/client-data.png\"><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/client-data.png\" alt=\"\" width=\"841\" height=\"423\" class=\"aligncenter size-full wp-image-55307\" srcset=\"\/wp-content\/uploads\/2026\/05\/client-data.png 841w, \/wp-content\/uploads\/2026\/05\/client-data-300x151.png 300w, \/wp-content\/uploads\/2026\/05\/client-data-768x386.png 768w, \/wp-content\/uploads\/2026\/05\/client-data-600x302.png 600w\" sizes=\"(max-width: 841px) 100vw, 841px\" \/><\/a><\/p>\n<p>\nOne thing to note here is that the OpenAI model is being used to generate music brief AND the music prompt. What&#8217;s the difference? Please, read the next section.\n<\/p>\n<h3 id=\"result-ui\">Result UI<\/h3>\n<p>\nOther than user input for IoT data snapshot, after successfully generating ambient music, the result user interface will render:\n<\/p>\n<ol>\n<li>Generated music prompt (+ Music bried details)<\/li>\n<li>Music player, it&#8217;s information, and the download link.<\/li>\n<\/ol>\n<p><a href=\"\/wp-content\/uploads\/2026\/05\/app-flow.png\"><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/app-flow.png\" alt=\"\" width=\"2354\" height=\"1692\" class=\"aligncenter size-full wp-image-55309\" srcset=\"\/wp-content\/uploads\/2026\/05\/app-flow.png 2354w, \/wp-content\/uploads\/2026\/05\/app-flow-300x216.png 300w, \/wp-content\/uploads\/2026\/05\/app-flow-1024x736.png 1024w, \/wp-content\/uploads\/2026\/05\/app-flow-768x552.png 768w, \/wp-content\/uploads\/2026\/05\/app-flow-1536x1104.png 1536w, \/wp-content\/uploads\/2026\/05\/app-flow-2048x1472.png 2048w, \/wp-content\/uploads\/2026\/05\/app-flow-370x265.png 370w, \/wp-content\/uploads\/2026\/05\/app-flow-600x431.png 600w\" sizes=\"(max-width: 2354px) 100vw, 2354px\" \/><\/a><\/p>\n<h3 id=\"history-ui\">History UI<\/h3>\n<p>\nWhen the user clicks the <strong>View History<\/strong> button, the app changes state to display all generated music, associated metadata, simplified IoT data, music briefs, and prompts.\n<\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/05\/music-history-scaled.png\"><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/music-history-scaled.png\" alt=\"\" width=\"2560\" height=\"1471\" class=\"aligncenter size-full wp-image-55296\" srcset=\"\/wp-content\/uploads\/2026\/05\/music-history-scaled.png 2560w, \/wp-content\/uploads\/2026\/05\/music-history-300x172.png 300w, \/wp-content\/uploads\/2026\/05\/music-history-1024x589.png 1024w, \/wp-content\/uploads\/2026\/05\/music-history-768x441.png 768w, \/wp-content\/uploads\/2026\/05\/music-history-1536x883.png 1536w, \/wp-content\/uploads\/2026\/05\/music-history-2048x1177.png 2048w, \/wp-content\/uploads\/2026\/05\/music-history-150x85.png 150w, \/wp-content\/uploads\/2026\/05\/music-history-600x345.png 600w\" sizes=\"(max-width: 2560px) 100vw, 2560px\" \/><\/a><\/p>\n<h2 id=\"generate-music-prompt\">Generate Music Prompt<\/h2>\n<h3 id=\"music-brief\">Music Brief<\/h3>\n<p>\nThis project generates a music brief before the final prompt to provide flexibility and a clear separation of concerns. The brief normalizes noisy IoT data into structured parameters, and the same brief can be reused with other (including non\u2011OpenAI) models without changing the mapping, making it robust for real\u2011world conditions.\n<\/p>\n<p>\nHere is an example of the music brief:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">{\r\n  &quot;mood&quot;: &quot;soothing&quot;,\r\n  &quot;energy&quot;: 48,\r\n  &quot;tension&quot;: 30,\r\n  &quot;bpm&quot;: [\r\n    50,\r\n    64\r\n  ],\r\n  &quot;duration_sec&quot;: 60,\r\n  &quot;loopable&quot;: true,\r\n  &quot;key_suggestion&quot;: &quot;A minor&quot;,\r\n  &quot;instrument_focus&quot;: [\r\n    &quot;warm pads&quot;,\r\n    &quot;soft piano&quot;,\r\n    &quot;breathy synth&quot;,\r\n    &quot;warm low strings&quot;,\r\n    &quot;subtle low percussion&quot;\r\n  ],\r\n  &quot;texture_notes&quot;: &quot;Airy, sparse texture with warm low mids and a gentle high-frequency roll-off to avoid brightness.&quot;,\r\n  &quot;rationale&quot;: &quot;CO2 &gt;1000 ppm and rising calls for lower-energy, soothing airiness; occupancy is low and temp\/humidity are ideal, so use sparse warm timbres and minimal rhythmic drive to reduce stress.&quot;\r\n}<\/code><\/pre>\n<\/div>\n<p>\nMusic brief generation is handled by <code>generateMusicBrief(sensorSnapshot)<\/code>. It takes a single IoT sensor snapshot and uses the OpenAI model gpt-5-mini to produce the brief. The full code can be found in the <code>lib\\openai.ts<\/code> file.\n<\/p>\n<p>\nThe important part of the code is the AI system prompt:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-js\">   const systemPrompt = `\r\nYou are an assistant that converts building sensor snapshots into a concise \u201cmusic brief\u201d for an ambient soundtrack generator.\r\nReturn ONLY compact JSON with these fields:\r\n{\r\n &quot;mood&quot;: &quot;calm|focused|energizing|soothing|alert|uplifting|neutral&quot;,\r\n &quot;energy&quot;: 0-100,\r\n &quot;tension&quot;: 0-100,\r\n &quot;bpm&quot;: [low, high],\r\n &quot;duration_sec&quot;: number,\r\n &quot;loopable&quot;: true|false,\r\n &quot;key_suggestion&quot;: &quot;A minor|D minor|C major|... (optional)&quot;,\r\n &quot;instrument_focus&quot;: [&quot;pads&quot;,&quot;soft piano&quot;,&quot;light percussion&quot;, ...],\r\n &quot;texture_notes&quot;: &quot;short sentence on space\/density\/brightness&quot;,\r\n &quot;rationale&quot;: &quot;1\u20132 sentences mapping readings\u2192choice&quot;\r\n}\r\n\r\nDecision rules:\r\n- High CO2 (&gt;1000 ppm) or high VOC (&gt;200) \u2192 lower energy (35\u201355), soothing\/airiness to reduce stress; avoid bright highs.\r\n- High occupancy (&gt;25) with good air (CO2 &lt; 800) \u2192 moderate energy (55\u201370) and gentle momentum; keep distractions low (no sharp transients).\r\n- High noise (&gt;60 dBA) \u2192 simpler textures, fewer rhythmic accents; tighten BPM range.\r\n- Productivity_score &lt; 60 \u2192 light uplift (energy +10), but stay minimal.\r\n- Temperature 22\u201324\u00b0C &amp; humidity 45\u201355% is ideal; if outside, reduce tension slightly and favor warm timbres.\r\nPrefer keys: minor for calming\/focus, major for uplifting.\r\nKeep outputs steady and minimal; no reactivity to single-sample spikes\u2014assume 10\u201315 min trend.\r\n`;<\/code><\/pre>\n<\/div>\n<p>\nThis system prompts the behaviour of the model AI to create a music brief with a pre-defined data structure using decision rules. If you want to enhance this project, this is the crucial part where you can adjust the decision rules to your requirements.\n<\/p>\n<h3 id=\"music-prompt\">Music Prompt<\/h3>\n<p>\nThe music prompt is generated using the <code>generateMusicPrompt(musicBrief)<\/code> function. This function will call the OpenAI model gpt-5-mini to generate a music prompt based on the music brief input.\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-js\">const response = await openai.responses.create({\r\n        model: &quot;gpt-5-mini&quot;,\r\n        input: [\r\n            { role: &quot;developer&quot;, content: [{ type: &quot;input_text&quot;, text: systemPrompt }] },\r\n            { role: &quot;user&quot;, content: [{ type: &quot;input_text&quot;, text: JSON.stringify(brief, null, 2) }] },\r\n        ],\r\n        text: { format: { type: &quot;text&quot; }, verbosity: &quot;medium&quot; },\r\n        reasoning: { effort: &quot;medium&quot;, summary: &quot;auto&quot; },\r\n        store: false,\r\n    } as any);<\/code><\/pre>\n<\/div>\n<p>\nWhat&#8217;s important here is the system prompt that is set in the AI model.\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">    const systemPrompt = `\r\nYou convert an internal JSON &quot;music brief&quot; into a concise prompt for a generative music API.\r\n\r\nRules:\r\n- Output 3\u20135 short lines, max ~450 characters total.\r\n- No meta commentary, no JSON, no emojis.\r\n- Include: mood, energy\/tension, BPM range, duration, loopable flag, (optional) key, instruments, texture, goal.\r\n- Avoid sharp\/bright transients when asked; keep language precise and production-safe.\r\n- Never invent values not present in the brief; default only when missing.\r\n\r\nExample:\r\n\r\n&quot;Ambient track for a focused open office. Mood: focused, energy 62\/100, tension 35\/100.\r\nTempo: 84\u201392 BPM, loopable, ~240s. Key: D minor.\r\nInstruments: warm pads, soft piano, light shaker, subtle bass.\r\nTexture: low-density, gentle movement, softened highs; avoid sharp transients and bright cymbals.\r\nGoal: steady momentum that supports concentration without masking speech.&quot;\r\n`;<\/code><\/pre>\n<\/div>\n<p>\nAgain, you can customize this system prompt to meet any of your custom project requirements before feeding it to music generation. The full source code for music prompt generation is in the <code>libs\\openai.ts<\/code> file.\n<\/p>\n<p>\nThis is an example of the generated music prompt:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">&quot;Calm. Energy 60\/100, tension 25\/100.\\nTempo: 58\u201364 BPM, duration ~60s, loopable. Key: A minor.\\nInstruments: warm pads, soft electric piano, subtle low bass, minimal brushed percussion.\\nTexture: sparse, warm, low\u2011mid focused with airy pads and subdued transients; avoid sharp\/bright transients to prevent masking ambient noise. Goal: gentle uplift and comfort without masking background.&quot;<\/code><\/pre>\n<\/div>\n<h2 id=\"generate-ambient-music\">Generate Ambient Music<\/h2>\n<p>\nAfter the music brief and music prompt generation, the next step is to generate the ambient music. This workflow handled by the <code>composeMusic()<\/code> function (full source code in the <code>libs\\elevenlabs.ts<\/code> file):\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">export async function composeMusic({\r\n  prompt,\r\n  music_length_ms = 60000,\r\n  model_id = &quot;music_v1&quot;,\r\n  apiKey = process.env.ELEVENLABS_API_KEY,\r\n}: ComposeParams): Promise&lt;ArrayBuffer&gt; {\r\n  if (!apiKey) {\r\n    throw new Error(&#x27;ElevenLabs API key not configured&#x27;);\r\n }\r\n\r\n  const response = await fetch(&quot;https:\/\/api.elevenlabs.io\/v1\/music&quot;, {\r\n    method: &quot;POST&quot;,\r\n    headers: {\r\n      &quot;xi-api-key&quot;: apiKey,\r\n      &quot;Content-Type&quot;: &quot;application\/json&quot;,\r\n },\r\n    body: JSON.stringify({ prompt, music_length_ms, model_id }),\r\n });\r\n\r\n  if (!response.ok) {\r\n    const errorText = await response.text();\r\n    const err: any = new Error(`ElevenLabs API error: ${errorText}`);\r\n    err.status = response.status;\r\n    throw err;\r\n }\r\n\r\n  return await response.arrayBuffer();\r\n}<\/code><\/pre>\n<\/div>\n<p>\nBasically, the code will call ElevenLabs Music API, which uses the latest <code>music_v1<\/code> model. However, in this project, the duration of the generated music is hardcoded to 60 seconds or 1 minute. You can edit this directly in the source code by changing the <code>music_length_ms = 60000<\/code> code.\n<\/p>\n<p>\nThe default audio output format from the ElevenLabs Music API is <code>mp3_44100_128<\/code>. The API also supports several other formats, for a complete list, refer to the official <a href=\"https:\/\/elevenlabs.io\/docs\/api-reference\/music\/compose\">documentation<\/a>.\n<\/p>\n<h2 id=\"database\">Database<\/h2>\n<p>\nThe container type used in this project is collection, and the schema for the data is defined by the interface <code>MusicGenerationRecord<\/code> code:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-js\">export interface MusicGenerationRecord {\r\n    timestamp: string;\r\n    zone: string;\r\n    temperature_c: number;\r\n    humidity_pct: number;\r\n    co2_ppm: number;\r\n    voc_index: number;\r\n    occupancy: number;\r\n    noise_dba: number;\r\n    productivity_score: number;\r\n    trend_10min_co2_ppm_delta: number;\r\n    trend_10min_noise_dba_delta: number;\r\n    trend_10min_productivity_delta: number;\r\n    music_brief: string;\r\n    music_prompt: string;\r\n    audio_path: string;\r\n    audio_filename: string;\r\n    music_length_ms: number;\r\n    model_id: string;\r\n    generation_timestamp: string;\r\n}<\/code><\/pre>\n<\/div>\n<p>\nAnd if you have access to the GridDB cloud dashboard, you will see these columns created based on the interface fields and their type.\n<\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/05\/griddb-columns.png\"><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/griddb-columns.png\" alt=\"\" width=\"1432\" height=\"843\" class=\"aligncenter size-full wp-image-55300\" srcset=\"\/wp-content\/uploads\/2026\/05\/griddb-columns.png 1432w, \/wp-content\/uploads\/2026\/05\/griddb-columns-300x177.png 300w, \/wp-content\/uploads\/2026\/05\/griddb-columns-1024x603.png 1024w, \/wp-content\/uploads\/2026\/05\/griddb-columns-768x452.png 768w, \/wp-content\/uploads\/2026\/05\/griddb-columns-600x353.png 600w\" sizes=\"(max-width: 1432px) 100vw, 1432px\" \/><\/a><\/p>\n<h3 id=\"save-data\">Save Data<\/h3>\n<p>\nThe save process will save the IoT data, music briefs, music prompts, audio path, audio filename, and timestamp on every successfull music generation and the function that responsible for this task is the <code>saveMusicGeneration(musicRecord)<\/code> function, initially it will check if the container <code>music_generations<\/code> exist or not and if exist than the data will be saved to the database.\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-js\">export async function saveMusicGeneration(record: MusicGenerationRecord): Promise&lt;void&gt; {\r\n    if (!GRIDDB_CONFIG.griddbWebApiUrl) {\r\n        console.warn(&#x27;\u26a0\ufe0f  GridDB not configured, skipping database save&#x27;);\r\n        return;\r\n }\r\n\r\n    await initGridDB();\r\n\r\n    try {\r\n        const client = getGridDBClient();\r\n        const containerName = &#x27;music_generations&#x27;;\r\n        console.log(`\ud83d\udcbe Saving music generation record for zone: ${record.zone}`);\r\n\r\n        \/\/ Generate a unique ID that fits in INTEGER range (max 2,147,483,647)\r\n        \/\/ Use a combination of current time modulo and random number\r\n        const timeComponent = Date.now() % 1000000; \/\/ Last 6 digits of timestamp\r\n        const randomComponent = Math.floor(Math.random() * 1000); \/\/ 3 digit random\r\n        const id = timeComponent * 1000 + randomComponent;\r\n\r\n        \/\/ Prepare the data object for insertion with proper date formatting\r\n        const data = {\r\n            id,\r\n            timestamp: new Date(record.timestamp),\r\n            zone: record.zone,\r\n            temperature_c: record.temperature_c,\r\n            humidity_pct: record.humidity_pct,\r\n            co2_ppm: record.co2_ppm,\r\n            voc_index: record.voc_index,\r\n            occupancy: record.occupancy,\r\n            noise_dba: record.noise_dba,\r\n            productivity_score: record.productivity_score,\r\n            trend_10min_co2_ppm_delta: record.trend_10min_co2_ppm_delta,\r\n            trend_10min_noise_dba_delta: record.trend_10min_noise_dba_delta,\r\n            trend_10min_productivity_delta: record.trend_10min_productivity_delta,\r\n            music_brief: record.music_brief,\r\n            music_prompt: record.music_prompt,\r\n            audio_path: record.audio_path,\r\n            audio_filename: record.audio_filename,\r\n            music_length_ms: record.music_length_ms,\r\n            model_id: record.model_id,\r\n            generation_timestamp: new Date(record.generation_timestamp)\r\n };\r\n\r\n        \/\/ Use the fixed insert method that now handles schema-aware transformation\r\n        await client.insert({\r\n            containerName,\r\n            data: data\r\n });\r\n\r\n        console.log(`\u2705 Music generation record saved to GridDB (ID: ${id}, Zone: ${record.zone}, File: ${record.audio_filename})`);\r\n } catch (error) {\r\n        console.error(&#x27;\u274c Failed to save music generation record:&#x27;, error);\r\n        throw error;\r\n }\r\n}<\/code><\/pre>\n<\/div>\n<h3 id=\"read-data\">Read Data<\/h3>\n<p>\nTo view the history of the music generations, it needs to read data from the database, and this task is internally handled by the <code>getMusicGenerations()<\/code> function.\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-js\">const client = getGridDBClient();\r\nconst containerName = &#x27;music_generations&#x27;;\r\nconsole.log(`\ud83d\udcca Retrieving ${limit} music generation records from GridDB`);\r\n\r\nconst results = await client.select({\r\n containerName,\r\n    orderBy: &#x27;generation_timestamp&#x27;,\r\n    order: &#x27;DESC&#x27;,\r\n limit\r\n});<\/code><\/pre>\n<\/div>\n<p>\nThe <code>client.select()<\/code> function is basically a wrapper for SQL SELECT. For the full source code for this function, you can look in the <code>libs\\griddb.ts<\/code> file.\n<\/p>\n<h2 id=\"nodejs-server\">Node.js Server<\/h2>\n<p>\nAll backend functionality is handled by the Node.js server. It exposes a few routes that can be used by the client application or for manual API testing.\n<\/p>\n<p><strong>Server Routes<\/strong><\/p>\n<table class=\"markdown-table\" style=\"border-collapse: collapse; width: 100%; margin: 1em 0;\">\n<thead>\n<tr>\n<th style=\"border: 1px solid #ddd; padding: 8px; background-color: #f2f2f2; text-align: left;\">Method<\/th>\n<th style=\"border: 1px solid #ddd; padding: 8px; background-color: #f2f2f2; text-align: left;\">Path<\/th>\n<th style=\"border: 1px solid #ddd; padding: 8px; background-color: #f2f2f2; text-align: left;\">Purpose<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\">GET<\/td>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\"><code>\/api\/health<\/code><\/td>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\">Health check with current timestamp<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\">POST<\/td>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\"><code>\/api\/iot\/generate-music<\/code><\/td>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\">Generate music based on the IoT data<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\">GET<\/td>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\"><code>\/api\/music\/history<\/code><\/td>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\">List past generations<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\nThis server also has a function to save the generated music file into the local <code>public\/audio<\/code> directory. It generates a clean MP3 filename using the <code>generateAudioFilename(zone, timestamp)<\/code> function and writes the audio buffer to <code>apps\/public\/audio\/<filename><\/code>. The function then returns the public URL path <code>\/audio\/<filename><\/code>.\n<\/p>\n<p>\nThe generated music is served as static files, so any <code>\/audio\/<filename>.mp3<\/code> URL is directly accessible over HTTP. You can open these files directly in a browser.\n<\/p>\n<h2 id=\"further-enhancements\">Further Enhancements<\/h2>\n<p>\nThis project is a simple prototype of what we can do using IoT, AI and the GridDB database. In the real scenario, you need to wire the app with real IoT sensor data.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to generate evolving ambient music driven by IoT sensor data. We\u2019ll ingest sensor readings into GridDB database, map those readings to musical parameters using OpenAI, and call ElevenLabs Music to render an audio track. The UI is built with React + Vite, and the backend is Node.js. Introduction Ambient music thrives [&hellip;]<\/p>\n","protected":false},"author":41,"featured_media":55305,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[121],"tags":[],"class_list":["post-55295","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Create Dynamic Ambient Music Using AI and IoT Data | GridDB: Open Source Time Series Database for IoT<\/title>\n<meta name=\"description\" content=\"This tutorial shows how to generate evolving ambient music driven by IoT sensor data. We\u2019ll ingest sensor readings into GridDB database, map those\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Create Dynamic Ambient Music Using AI and IoT Data | GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"og:description\" content=\"This tutorial shows how to generate evolving ambient music driven by IoT sensor data. We\u2019ll ingest sensor readings into GridDB database, map those\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/\" \/>\n<meta property=\"og:site_name\" content=\"GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/griddbcommunity\/\" \/>\n<meta property=\"article:published_time\" content=\"2026-05-21T17:58:14+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-05-28T18:07:14+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.griddb.net\/wp-content\/uploads\/2026\/05\/cover.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1536\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"griddb-admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:site\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"griddb-admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/\"},\"author\":{\"name\":\"griddb-admin\",\"@id\":\"https:\/\/www.griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\"},\"headline\":\"Create Dynamic Ambient Music Using AI and IoT Data\",\"datePublished\":\"2026-05-21T17:58:14+00:00\",\"dateModified\":\"2026-05-28T18:07:14+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/\"},\"wordCount\":1716,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.griddb.net\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2026\/05\/cover.png\",\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/\",\"url\":\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/\",\"name\":\"Create Dynamic Ambient Music Using AI and IoT Data | GridDB: Open Source Time Series Database for IoT\",\"isPartOf\":{\"@id\":\"https:\/\/www.griddb.net\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2026\/05\/cover.png\",\"datePublished\":\"2026-05-21T17:58:14+00:00\",\"dateModified\":\"2026-05-28T18:07:14+00:00\",\"description\":\"This tutorial shows how to generate evolving ambient music driven by IoT sensor data. We\u2019ll ingest sensor readings into GridDB database, map those\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#primaryimage\",\"url\":\"\/wp-content\/uploads\/2026\/05\/cover.png\",\"contentUrl\":\"\/wp-content\/uploads\/2026\/05\/cover.png\",\"width\":1536,\"height\":1024},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.griddb.net\/en\/#website\",\"url\":\"https:\/\/www.griddb.net\/en\/\",\"name\":\"GridDB: Open Source Time Series Database for IoT\",\"description\":\"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL\",\"publisher\":{\"@id\":\"https:\/\/www.griddb.net\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.griddb.net\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.griddb.net\/en\/#organization\",\"name\":\"Fixstars\",\"url\":\"https:\/\/www.griddb.net\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.griddb.net\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"contentUrl\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"width\":200,\"height\":83,\"caption\":\"Fixstars\"},\"image\":{\"@id\":\"https:\/\/www.griddb.net\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/griddbcommunity\/\",\"https:\/\/x.com\/GridDBCommunity\",\"https:\/\/www.linkedin.com\/company\/griddb-by-toshiba\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\",\"name\":\"griddb-admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.griddb.net\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"caption\":\"griddb-admin\"},\"url\":\"https:\/\/www.griddb.net\/en\/author\/griddb-admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Create Dynamic Ambient Music Using AI and IoT Data | GridDB: Open Source Time Series Database for IoT","description":"This tutorial shows how to generate evolving ambient music driven by IoT sensor data. We\u2019ll ingest sensor readings into GridDB database, map those","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/","og_locale":"en_US","og_type":"article","og_title":"Create Dynamic Ambient Music Using AI and IoT Data | GridDB: Open Source Time Series Database for IoT","og_description":"This tutorial shows how to generate evolving ambient music driven by IoT sensor data. We\u2019ll ingest sensor readings into GridDB database, map those","og_url":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/","og_site_name":"GridDB: Open Source Time Series Database for IoT","article_publisher":"https:\/\/www.facebook.com\/griddbcommunity\/","article_published_time":"2026-05-21T17:58:14+00:00","article_modified_time":"2026-05-28T18:07:14+00:00","og_image":[{"width":1536,"height":1024,"url":"https:\/\/www.griddb.net\/wp-content\/uploads\/2026\/05\/cover.png","type":"image\/png"}],"author":"griddb-admin","twitter_card":"summary_large_image","twitter_creator":"@GridDBCommunity","twitter_site":"@GridDBCommunity","twitter_misc":{"Written by":"griddb-admin","Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#article","isPartOf":{"@id":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/"},"author":{"name":"griddb-admin","@id":"https:\/\/www.griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233"},"headline":"Create Dynamic Ambient Music Using AI and IoT Data","datePublished":"2026-05-21T17:58:14+00:00","dateModified":"2026-05-28T18:07:14+00:00","mainEntityOfPage":{"@id":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/"},"wordCount":1716,"commentCount":0,"publisher":{"@id":"https:\/\/www.griddb.net\/en\/#organization"},"image":{"@id":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2026\/05\/cover.png","articleSection":["Blog"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/","url":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/","name":"Create Dynamic Ambient Music Using AI and IoT Data | GridDB: Open Source Time Series Database for IoT","isPartOf":{"@id":"https:\/\/www.griddb.net\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#primaryimage"},"image":{"@id":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2026\/05\/cover.png","datePublished":"2026-05-21T17:58:14+00:00","dateModified":"2026-05-28T18:07:14+00:00","description":"This tutorial shows how to generate evolving ambient music driven by IoT sensor data. We\u2019ll ingest sensor readings into GridDB database, map those","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.griddb.net\/en\/blog\/create-dynamic-ambient-music-using-ai-and-iot-data\/#primaryimage","url":"\/wp-content\/uploads\/2026\/05\/cover.png","contentUrl":"\/wp-content\/uploads\/2026\/05\/cover.png","width":1536,"height":1024},{"@type":"WebSite","@id":"https:\/\/www.griddb.net\/en\/#website","url":"https:\/\/www.griddb.net\/en\/","name":"GridDB: Open Source Time Series Database for IoT","description":"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL","publisher":{"@id":"https:\/\/www.griddb.net\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.griddb.net\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.griddb.net\/en\/#organization","name":"Fixstars","url":"https:\/\/www.griddb.net\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.griddb.net\/en\/#\/schema\/logo\/image\/","url":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","contentUrl":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","width":200,"height":83,"caption":"Fixstars"},"image":{"@id":"https:\/\/www.griddb.net\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/griddbcommunity\/","https:\/\/x.com\/GridDBCommunity","https:\/\/www.linkedin.com\/company\/griddb-by-toshiba"]},{"@type":"Person","@id":"https:\/\/www.griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233","name":"griddb-admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.griddb.net\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","caption":"griddb-admin"},"url":"https:\/\/www.griddb.net\/en\/author\/griddb-admin\/"}]}},"_links":{"self":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/55295","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/comments?post=55295"}],"version-history":[{"count":3,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/55295\/revisions"}],"predecessor-version":[{"id":55310,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/55295\/revisions\/55310"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/media\/55305"}],"wp:attachment":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/media?parent=55295"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/categories?post=55295"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/tags?post=55295"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}