Final project – Hamdah AlSuwaidi

The project’s concept:

The allure of a jukebox, with its nostalgic charm and tangible interaction with music selection, inspires a unique blend of past and present in your project. This modern reinterpretation of the classic jukebox isn’t just about listening to music—it’s an experiential dive into the ritual of choosing sounds from different eras and styles, echoing the tactile joy that came from flipping through vinyl records or pressing the physical buttons on a jukebox. Your project revives this delightful sensory interaction by blending physical buttons and digital outputs, allowing users to actively engage with the music rather than passively streaming playlists. It embodies a revival of the golden age of jukeboxes but with a contemporary twist, using today’s technology to recreate a piece of the past that resonates with both nostalgia and the new digital era.

The decision to incorporate a variety of music channels such as English, Classical, and Al Khalidiya channels suggests a celebration of diversity and the rich tapestry of global music culture. It reflects a yearning to bring the world closer together through the universal language of music, wrapped in the classic format of a jukebox. This project does more than just play music; it invites users to journey through different cultures and time periods at the push of a button. It’s a bridge between generations and geographies, enabling a shared experience that is both educational and entertaining, which is likely what sparked the idea to reinvent the jukebox for a modern audience. This blend of educational purpose and entertainment, rooted in technological innovation, makes your jukebox project a meaningful nod to the past while eagerly embracing the future of interactive media.

P5js code:

// Initial state settings
let loading = true;
let channels = [[], [], []]; // Arrays for storing songs by channel: 0 - English, 1 - Classical, 2 - Al Khalidiya
let numberOfSongs = 0;
let numberOfSongsLoaded = 0; 
let coinSound; // Sound effect for the coin insert
let selectedChannel; // Currently selected channel
let playing = false; // Is a song currently playing?
let songToPlay; // Current song playing

// Preload function to load sounds and other resources before the program starts
function preload() {
  soundPaths = loadStrings("soundFileNames.txt"); // Load list of sound file names
  coinSound = loadSound("sounds/coin.mp3"); // Load coin sound effect
}

// Setup function to initialize the environment
function setup() {
  createCanvas(600, 400);
  textAlign(CENTER, CENTER);

  // Loop through the sound paths and assign them to channels based on file names
  for (let i = 0; i < soundPaths.length; i++) {
    let words = soundPaths[i].split("_");
    let channel = words[words.length - 2] + "_" + words[words.length - 1]; // Determine the channel from the file name
    switch (channel) {
      case "english_channel.mp3":
        channels[0].push("sounds/" + words.join("_"));
        break;
      case "classical_channel.mp3":
        channels[1].push("sounds/" + words.join("_"));
        break;
      case "khalidiya_channel.mp3":
        channels[2].push("sounds/" + words.join("_"));
        break;
    }
  }
  numberOfSongs = soundPaths.length; // Total number of songs loaded
  // Load each song in the channels array
  for (let i = 0; i < channels.length; i++) {
    for (let j = 0; j < channels[i].length; j++) {
      channels[i][j] = loadSound(channels[i][j], () => {
        numberOfSongsLoaded += 1; // Increment the count of loaded songs
      });
    }
  }
  ratioPos = { x: width / 2, y: height * 2 };
  selectedChannel = floor(random(3)); // Randomly select a channel to start
  fft = new p5.FFT(); // Initialize Fast Fourier Transform for audio visualization
}

// Draw function to continuously execute and render the canvas
function draw() {
  background(40);
  if (loading) {
    // Show loading screen until all songs are loaded
    rectMode(CORNER);
    strokeWeight(2);
    textSize(34);
    fill(255);
    text("LOADING...", width / 2, height / 2 - 20);
    noStroke();
    fill(255);
    rect(width / 2 - 150, height / 2 + 20, 300, 40);
    fill(20);
    rect(
      width / 2 - 150,
      height / 2 + 20,
      map(numberOfSongsLoaded, 0, numberOfSongs, 0, 300),
      40
    );
    if (numberOfSongsLoaded == numberOfSongs) {
      loading = false;
    }
  } else {
    // Display the sound spectrum and UI once loading is complete
    let wave = fft.waveform();
    stroke(255, 50);
    noFill();
    beginShape();
    for (let i = 0; i < wave.length; i++) {
      let x = map(i, 0, wave.length, 0, width);
      let y = map(wave[i], -1, 1, height, 0);
      curveVertex(x, y);
    }
    endShape();

    rectMode(CENTER);
    ratioPos.y = lerp(ratioPos.y, height / 2, 0.1); // Smoothly move the UI element
    textSize(16);
    let channelName = "";
    switch (selectedChannel) { // Display the name of the selected channel
      case 0:
        channelName = " ENGLISH SONGS ";
        break;
      case 1:
        channelName = " CLASSICAL SONGS ";
        break;
      case 2:
        channelName = " KHALIDIYA SONGS ";
        break;
    }
    drawRadio(channelName, playing);
    drawChannels();
  }
}

// Event-driven functions to respond to keyboard presses for controlling the jukebox
function keyPressed() {
  switch (key) {
    case "n":
      nextChannel(); // Go to the next channel
      stopMusic(); // Stop the currently playing music
      break;
    case "b":
      prevChannel(); // Go to the previous channel
      stopMusic(); // Stop the music
      break;
    case " ":
      if (!playing) {
        playMusic(); // Start playing music if not already playing
      } else {
        stopMusic(); // Stop the music if playing
      }
      break;
  }
}

// Utility functions to control channels and playback
function nextChannel() {
  selectedChannel += 1; // Increment the channel index
  if (selectedChannel >= 3) {
    selectedChannel = 0; // Wrap around to the first channel
  }
}
function prevChannel() {
  selectedChannel -= 1; // Decrement the channel index
  if (selectedChannel < 0) {
    selectedChannel = 2; // Wrap around to the last channel
  }
}
function stopMusic() {
  if (songToPlay) {
    songToPlay.stop(); // Stop the currently playing song
  }
  playing = false;
}
function playMusic() {
  coinSound.play(); // Play the coin sound effect
  songToPlay = random(channels[selectedChannel]); // Select a random song from the current channel
  playing = true;
  songToPlay.loop(); // Start playing the selected song
}

// Drawing utility functions for UI elements
function drawChannels() {
  fill(100, 120, 100);
  rect(0, 150, 320, 70);
  fill(60, 70, 60);
  rect(0, 150, 300, 50);
  push();
  textAlign(LEFT, CENTER);
  let channels = ["English", "Classical", "Khalidiya"];
  textSize(12);
  for (let i = 0; i < 3; i++) {
    let x = 0;
    let y = 130 + 20 * i;
    noFill();
    if (selectedChannel == i) {
      fill(60, 90, 60);
      rect(x, y, 300, 15);
      fill(120, 150, 120);
      text("_" + channels[i], x - 150, y);
    } else {
      rect(x, y, 300, 15);
      fill(120, 150, 120);
      text(" " + channels[i], x - 150, y);
    }
  }
  pop();
}

// Function to draw the radio interface
function drawRadio(channel, playing = false) {
  translate(ratioPos.x, ratioPos.y);
  // Visual elements for the radio disk
  noStroke();
  fill(150, 150, 220, 100);
  circle(0, 100, 450);

  fill(20);
  circle(0, 100, 350);
  fill(200, 100, 100);
  circle(0, 100, 150);

  let channelName = channel.split("");
  push();
  translate(0, 100);
  if (playing) rotate(-frameCount / 60);
  push();
  for (let i = 0; i in channelName.length; i++) {
    rotate(TWO_PI / channelName.length);
    fill(255);
    text(channelName[i].toUpperCase(), 0, -50);
  }

  pop();
  pop();
  fill(180);
  circle(0, 100, 80);

  stroke(255);
  noFill();
  arc(0, 100, 420, 420, -PI / 2 + 0.4, -PI / 2 + 0.8);

  noStroke();
  strokeWeight(2);
  fill("#606A42");
  rect(0, 290, 500, 400, 40);
}

code with Arduino:

let loading = true;
let channels = [[], [], []]; //0 english channel , 1 - classical channel, 2 Al Khalidiya channel
let numberOfSongs = 0;
let numberOfSongsLoaded = 0;
let coinSound;
let selectedChannel;
let playing = false;
let songToPlay;
let toSend = 0;

function preload() {
  soundPaths = loadStrings("soundFileNames.txt");
  coinSound = loadSound("sounds/coin.mp3");

  // for (let i = 0; i < soundPaths.length; i++) {
  //   let words = soundPaths[i].split("_");
  //   //here we'll store sound paths in different arrays as different channels
  //   let channel = words[words.length - 2] + "_" + words[words.length - 1];
  //   switch (channel) {
  //     case "english_channel.mp3":
  //       channels[0].push("sounds/" + words.join("_"));
  //       break;
  //     case "classical_channel.mp3":
  //       channels[1].push("sounds/" + words.join("_"));
  //       break;
  //     case "khalidiya_channel.mp3":
  //       channels[2].push("sounds/" + words.join("_"));
  //       break;
  //   }
  // }
  // print(channels)
  // numberOfSongs = soundPaths.length;
  // //load every song in channel
  // for (let i = 0; i < channels.length; i++) {
  //   for (let j = 0; j < channels[i].length; j++) {
  //     channels[i][j] = loadSound(channels[i][j], () => {
  //       numberOfSongsLoaded += 1;
  //     });
  //   }
  // }
  /*
  ahlam_al_khalidiya_channel.mp3
cello_suite_classical_channel.mp3
gabl _aaarfak_al_khalidiya_channel.mp3
gymnopédie_classical_channel.mp3
i_lived_english_channel.mp3
mushfi_jorouhi_al_khalidiya_channel.mp3
overture_classical_channel.mp3
raheeb__al_khalidiya_channel.mp3
rouhe_thebak_al_khalidiya_channel.mp3
sundress_english_channel.mp3
swan_lake_suite_classical_channel.mp3
// sza_english_channel.mp3
virginia_beach_english_channel.mp3
whats_on_ur_mind_english_channel.mp3
  */

  {
    let sound = loadSound("sounds/i_lived_english_channel.mp3");
    channels[0].push(sound);
  }

  {
    let sound = loadSound("sounds/virginia_beach_english_channel.mp3");
    channels[0].push(sound);
  }
  
   
 


  
  
  
  
  
  
  
  
}

function setup() {
  createCanvas(600, 400);
  textAlign(CENTER, CENTER);

  //
  ratioPos = { x: width / 2, y: height * 2 };
  selectedChannel = floor(random(3));
  fft = new p5.FFT();
}

function draw() {
  background(40);
  if (loading) {
    rectMode(CORNER);
    strokeWeight(2);
    textSize(34);
    fill(255);
    text("LOADING...", width / 2, height / 2 - 20);
    noStroke();
    fill(255);
    rect(width / 2 - 150, height / 2 + 20, 300, 40);
    fill(20);
    rect(
      width / 2 - 150,
      height / 2 + 20,
      map(numberOfSongsLoaded, 0, numberOfSongs, 0, 300),
      40
    );
    if (numberOfSongsLoaded == numberOfSongs) {
      loading = false;
    }
  } else {
    //
    //draw Sound Spectrum
    let wave = fft.waveform();
    stroke(255, 50);
    noFill();
    beginShape();
    let x, y;
    for (let i = 0; i < wave.length; i++) {
      x = map(i, 0, wave.length, 0, width);
      y = map(wave[i], -1, 1, height, 0);
      curveVertex(x, y);
    }
    endShape();

    rectMode(CENTER);
    ratioPos.y = lerp(ratioPos.y, height / 2, 0.1);
    textSize(16);
    let channelName = "";
    switch (selectedChannel) {
      case 0:
        channelName = " ENGLISH SONGS ";
        break;
      case 1:
        channelName = " CLASSICAL SONGS ";
        break;
      case 2:
        channelName = " KHALIDIYA SONGS ";
        break;
    }
    drawRadio(channelName, playing);
    drawChannels();
  }
}

//functions to call from arduino's button
function keyPressed() {
  switch (key) {
    case "n":
      nextChannel();
      stopMusic();
      break;
    case "b":
      prevChannel();
      stopMusic();
      break;
    case " ":
      if (!playing) {
        playMusuc();
      } else {
        stopMusic();
      }
      break;
  }
}

function nextChannel() {
  selectedChannel += 1;
  if (selectedChannel >= 3) {
    selectedChannel = 0;
  }
}
function prevChannel() {
  selectedChannel -= 1;
  if (selectedChannel < 0) {
    selectedChannel = 2;
  }
}
function stopMusic() {
  if (songToPlay) {
    songToPlay.stop();
  }
  playing = false;
}
function playMusuc() {
  if (!playing) {
    coinSound.play();
    print("sel: " + selectedChannel);
    songToPlay = channels[selectedChannel][Math.floor(random(3))]; //random(channels[selectedChannel]);
    playing = true;
    songToPlay.loop();
  }
}

function drawChannels() {
  fill(100, 120, 100);
  rect(0, 150, 320, 70);
  fill(60, 70, 60);
  rect(0, 150, 300, 50);
  push();
  textAlign(LEFT, CENTER);
  let channels = ["English", "Classical", "Khalidiya"];
  textSize(12);
  for (let i = 0; i < 3; i++) {
    // text(channels[i],20,40+15*i);
    let x = 0;
    let y = 130 + 20 * i;
    noFill();
    if (selectedChannel == i) {
      fill(60, 90, 60);
      rect(x, y, 300, 15);
      fill(120, 150, 120);
      text("_" + channels[i], x - 150, y);
    } else {
      rect(x, y, 300, 15);
      fill(120, 150, 120);
      text(" " + channels[i], x - 150, y);
    }
  }
  pop();
}

function drawRadio(channel, playing = false) {
  translate(ratioPos.x, ratioPos.y);
  //disk
  noStroke();
  fill(150, 150, 220, 100);
  circle(0, 100, 450);

  fill(20);
  circle(0, 100, 350);
  fill(200, 100, 100);
  circle(0, 100, 150);

  let channelName = channel.split("");
  push();
  translate(0, 100);
  if (playing) rotate(-frameCount / 60);
  push();
  for (let i = 0; i < 20; i++) {
    rotate(TWO_PI / 20);
    fill(255);
    text("_", 0, -170);
  }
  pop();
  push();
  for (let i = 0; i < channelName.length; i++) {
    rotate(TWO_PI / channelName.length);
    fill(255);
    text(channelName[i].toUpperCase(), 0, -50);
  }

  pop();
  pop();
  fill(180);
  circle(0, 100, 80);

  stroke(255);
  noFill();
  arc(0, 100, 420, 420, -PI / 2 + 0.4, -PI / 2 + 0.8);

  noStroke();
  strokeWeight(2);
  fill("#606A42");
  rect(0, 290, 500, 400, 40);
}

function readSerial(data) {
  ////////////////////////////////////
  //READ FROM ARDUINO HERE
  ////////////////////////////////////

  if (data != null) {
    print(data);
    // make sure there is actually a message
    // split the message
    let fromArduino = split(trim(data), ",");
    // if the right length, then proceed
    if (fromArduino.length == 4) {
      // only store values here
      // do everything with those values in the main draw loop

      // We take the string we get from Arduino and explicitly
      // convert it to a number by using int()
      // e.g. "103" becomes 103
      let start = int(fromArduino[0]);
      let stop = int(fromArduino[1]);
      let next = int(fromArduino[2]);
      let prev = int(fromArduino[3]);

      if (start == 1) {
        print("start");
        playMusuc();
      } else if (stop == 1) {
        print("stop");
        stopMusic();
      } else if (next == 1) {
        print("next");
        nextChannel();
        stopMusic();
      } else if (prev == 1) {
        print("prev");
        prevChannel();
        stopMusic();
      }

      //////////////////////////////////
      //SEND TO ARDUINO HERE (handshake)
      //////////////////////////////////
      let sendToArduino = 0 + "\n";
      writeSerial(sendToArduino);
    }
  }
}

function keyPressed() {
  if (key == " ") {
    // important to have in order to start the serial connection!!
    setUpSerial();
  }
}

Showcase:

Struggles:

When I initially incorporated Arduino buttons into the program, I envisioned a seamless integration that would enhance the user experience by providing tangible controls for the digital jukebox. However, this integration proved to be more challenging than anticipated. The entire program malfunctioned, leading to unexpected behaviors where buttons would either not respond or trigger incorrect actions. This technical hurdle was a significant setback, as it compromised the core functionality of the project—interacting with the music playlist through physical controls.

Faced with these difficulties, I realized that a pivot was necessary to maintain the integrity and usability of the project. I revisited the drawing board, reevaluating the interfacing between the Arduino and the software. This required stripping down complex parts of the code, simplifying the communication protocols, and implementing more robust error handling mechanisms to ensure that each button press accurately corresponded to the intended action. Although this pivot was a detour from my original vision, it was a crucial learning experience that emphasized the importance of adaptability and thorough testing in the development process. The revamped approach not only resolved the issues but also reinforced the project’s functionality, making it more reliable and user-friendly.

Future Improvements:

Based on the experiences and challenges encountered with the integration of Arduino buttons and the development of the digital jukebox, several future improvements can be outlined to enhance the project further:

1. Enhanced Error Handling and Debugging Tools: Implementing more sophisticated error handling mechanisms can help identify and resolve issues more efficiently when they arise during the interaction between the Arduino hardware and the software. Additionally, developing a suite of debugging tools or visual indicators in the software can help monitor the state and health of the system in real-time.

2. User Interface Improvements: Enhancing the user interface to provide clearer feedback and more intuitive controls can significantly improve the user experience. This could include visual indicators of button presses, more responsive animations, or a more aesthetically pleasing layout that mimics the classic jukebox style.

3. Expanded Music Library and Categorization: Expanding the music library to include more diverse genres and new channels can cater to a broader audience. Implementing a more dynamic categorization system where users can create custom playlists or choose from themed channels could add a new layer of interaction.

4. Wireless Control Options: Introducing wireless control options such as Bluetooth or Wi-Fi connectivity could allow users to control the jukebox from their smartphones or other devices. This could be particularly useful for accessibility purposes and to accommodate larger venues.

5. Improved Audio Quality and Effects: Upgrading the sound output hardware or integrating software that allows for better sound equalization and effects can enhance the overall listening experience. This might include features like bass boost, echo, and balance adjustments that users can control directly.

6. Sustainability and Maintenance: Considering the long-term sustainability and ease of maintenance in the design can ensure the jukebox remains functional and enjoyable for years. This could involve using more durable materials for the hardware, making the system modular for easy repairs, or providing software updates to keep the system secure and efficient.

7. Interactive Features and Gamification: Introducing interactive features such as music trivia, user contests, or gamification elements where users can earn points or rewards for their interaction can increase engagement and provide a more entertaining experience.

These improvements aim to refine the functionality, broaden the appeal, and ensure the longevity of the digital jukebox project, making it not only a nostalgic piece but a cutting-edge feature for any social or personal space.

Arduino code:

// Define the pin numbers for the buttons
const int pinGreen = 11; // Start
const int pinYellow = 9; // Stop
const int pinBlue = 5; // Next Channel
const int pinBlack = 3; // Previous Channel

void setup() {
  // Initialize the buttons as inputs
  pinMode(pinGreen, INPUT);
  pinMode(pinYellow, INPUT);
  pinMode(pinBlue, INPUT);
  pinMode(pinBlack, INPUT);

  // Start serial communication at 9600 bps
  Serial.begin(9600);
  // start the handshake
  while (Serial.available() <= 0) {
    Serial.println("0,0,0,0"); // send a starting message
    delay(50);
  }
}

void loop() {
  // Read the state of each button
  int stateGreen = digitalRead(pinGreen);
  int stateYellow = digitalRead(pinYellow);
  int stateBlue = digitalRead(pinBlue);
  int stateBlack = digitalRead(pinBlack);
  // Serial.println(toSend);

  // String toSend;

  // Send different commands based on button presses
  // if (stateGreen == HIGH) {
  //   toSend = "start";
  // }
  // else if (stateYellow == HIGH) {
  //   Serial.println("stop"); // Command to stop the radio
  // }
  // else if (stateBlue == HIGH) {
  //   Serial.println("next"); // Command to go to next channel
  // }
  // else if (stateBlack == HIGH) {
  //   Serial.println("prev"); // Command to go to previous channel
  // }

  while (Serial.available()) {
    int fromP5 = Serial.parseInt();
   
    if (Serial.read() == '\n') {
      Serial.print(stateGreen);
      Serial.print(",");
      Serial.print(stateYellow);
      Serial.print(",");
      Serial.print(stateBlue);
      Serial.print(",");
      Serial.println(stateBlack);
    }
  }

  // delay(100); // Delay to debounce and prevent multiple sends
}

 

Reading response week 12 – Hamdah AlSuwaidi

The reading from “Design Meets Disability” suggests a profound paradigm shift in the approach to design, particularly for products meant to be accessible for all, including those with disabilities. This shift moves away from a focus on mere functionality and discretion toward a more holistic view that embraces aesthetic appeal, personal identity, and cultural relevance.

The text draws attention to the meticulous process behind achieving the apparent simplicity of designs like the iPod, which balances minimalism with functionality and accessibility. It emphasizes the idea that while simplicity in design is often celebrated, the complexity involved in achieving it is substantial and not necessarily apparent to the end-user.

Further discussed is the idea of “spimes,” a term coined by Bruce Sterling to describe objects that are more than their physical form; they are information-rich, context-aware, and sustainable. This represents a vision of the future where products are integrated into our lives in a way that is both meaningful and mindful of the larger ecological and informational ecosystems they inhabit.

Moreover, the reading posits that designs should not be solely driven by the technological capability or the imperative of universality but should consider the nuanced needs and preferences of individual users, which includes emotional and psychological responses. It illustrates that designing for disability isn’t just about providing a function; it’s about creating an experience and empowering the user.

the challenge presented to designers: to forge a path that neither patronizes nor alienates but instead enriches the user’s life. It calls for a commitment to design that is not only inclusive in its utility but also in its beauty and its ability to resonate with users on a personal level. The aim is to push the envelope of what is possible, creating products that are not just usable by everyone but also desirable by everyone, thus fostering a more inclusive and empathetic society.

Reading response / Final proposal – Hamdah Alsuwaidi

Reading response:

The narrative woven through the author’s critique and subsequent responses to reader feedback forms a cohesive argument for a transformative approach to interaction design. At the core of this discussion is a pointed critique of the reliance on touchscreens, or what the author refers to as “Pictures Under Glass.” This approach, the author argues, falls short of engaging the full spectrum of human abilities, especially the tactile and manipulative capacities intrinsic to the human experience.

Bringing expertise from a background in designing future interfaces, the author offers a credible perspective on the limitations of current technological trends and makes a clarion call for a reevaluation of our design ethos. The focus is on creating interfaces that not only address problems but also resonate with the rich physical faculties innate to users, suggesting that tools should amplify human capabilities and serve as an extension of human experience rather than its reduction.

The response to critiques emphasizes that the author’s original “rant” was not a dismissal of current devices like iPhones or iPads but a push for acknowledging their current utility while recognizing the imperative for future developments to transcend these existing paradigms. The author envisages a future where technology could tangibly represent and manipulate the environment in ways yet to be discovered, leveraging long-term research.

Voice interfaces, while useful, are seen as insufficient for fostering the depth of creativity and understanding that comes from a more tactile and hands-on interaction. Similarly, gestural interfaces and brain interfaces that circumvent the full use of the body are met with skepticism. The author stresses the need for interfaces that don’t make us sedentary or immobile, advocating against creating a future where interaction is disembodied.

In a profound reflection on the accessibility and apparent simplicity of touchscreens, the author warns against mistaking ease of use for comprehensive engagement, noting that while a two-year-old can swipe a touchscreen, such interaction doesn’t fully capitalize on adult capabilities.

Combining these perspectives, the author’s message is a wake-up call for designers, technologists, and visionaries. It’s an urging to reimagine interaction with the digital world in a way that brings our physical interaction with technology into a harmonious synergy, maximizing rather than diluting our human potential. This combined narrative is not just a response to current technological trends but a hopeful blueprint for the future of interaction design that is as rich and complex as the capabilities it aims to serve.

Final proposal:

Concept:
An Interactive Digital Jukebox, merges the nostalgic allure of classic jukeboxes with the functionalities of modern digital technology. Utilizing Arduino Uno for hardware control and p5.js for interactive web-based visualizations, this project aims to deliver a user-friendly music player that offers both physical and web interfaces for song selection, volume control, and music visualization.

Project Description:
The Interactive Digital Jukebox allows users to select and play music tracks from a stored library, offering real-time audio visualizations and track information through a p5.js . The system combines simple physical components for user interaction with sophisticated web-based graphics, creating a multifaceted entertainment device.

Components:
– SD Card Module: For storage and retrieval of MP3 music files.
– LCD Screen: To display track information directly on the device.
– Push Buttons: For navigating the music library and controlling playback.
– Speakers/Headphone Jack: To output audio.
– Potentiometer: To manually adjust the volume.

Functionality:
1. Music Playback: Music files stored on the SD card will be accessed and controlled via Arduino, with support for basic functions like play, pause, skip, and back.
2. User Interface: The p5.js interface will display a list of tracks, currently playing song details, and interactive playback controls.
3. Visual Feedback: The web interface will include dynamic visualizations corresponding to the music’s audio features, such as volume and frequency spectrum.
4. Physical Controls: Physical interactions will be enabled through push buttons or a touch screen connected to the Arduino.
5. Volume Control: A potentiometer will allow users to adjust the sound volume, with changes reflected both physically and on the web interface.

Implementation Steps:
1. SD Card Reader Setup: Install the SD card module to the Arduino and load it with MP3 files. Program the Arduino to use an MP3 decoder library for playback control.
2. Control Interface Development: Configure the input mechanisms (buttons, potentiometer) and ensure their functional integrity for user interaction.
3. Web Interface Creation: Develop the visual and interactive components of the p5.js interface, including song listings, playback controls, and visualization areas.
4. Audio Visualization Integration: Utilize the `p5.sound` library to analyze audio signals and generate corresponding visual effects on the web interface.
5. System Integration: Establish robust communication between Arduino and the p5.js application, likely via serial communication.

By bringing together the tactile satisfaction of traditional jukeboxes with the visual appeal and interactivity of modern interfaces, this project stands to offer not just a practical entertainment solution but also an educational tool that demonstrates the integration of different technologies. It promises to be an excellent demonstration of skills in both electronics and software development, appealing to a broad audience and fostering a deeper appreciation for the fusion of old and new media technologies.

 

 

 

 

 

Melody steps – (Hamdah, Shaikha, shereena)

Concept: 

Replicating the piano playing mat that we all used to play as children was the idea behind this assignment. Even those who are not musically inclined are drawn to play with the piano mat again because of how logically it was created. Why not make something that makes us all feel nostalgic, rather than just one of us? You’ll be overwhelmed with happiness as you play about with our design and hopefully be able to relive all your childhood memories in a way. This initiative will facilitate audience engagement and provide a means of connection to one another. 

https://youtu.be/Epy7WpZjhno

Code:

The code is for an Arduino setup that uses an ultrasonic sensor to measure distance and a force-sensitive resistor to detect pressure. It plays different musical notes based on the distance measured by the sensor, but only if a certain pressure threshold is exceeded on the resistor. If the measured distance is out of a specified range or the pressure is too low, no sound is played. The system uses this setup to create an interactive musical device where sound changes with distance and pressure.

 

int trig = 10;

int echo = 11;

long duration;

long distance;

int force;



void setup() {

  pinMode(echo, INPUT);



  pinMode(trig, OUTPUT);



  Serial.begin(9600);

}



void loop() {

  digitalWrite(trig, LOW); //triggers on/off and then reads data

  delayMicroseconds(2);

  digitalWrite(trig, HIGH);

  delayMicroseconds(10);

  digitalWrite(trig, LOW);

  duration = pulseIn(echo, HIGH);

  distance = (duration / 2) * .0344;    //344 m/s = speed of sound. We're converting into cm





  int notes[7] = {261, 294, 329, 349, 392, 440, 494}; //Putting several notes in an array

  //          mid C  D   E   F   G   A   B



  force = analogRead(A0); //defining force as FSR data




  if (distance < 0 || distance > 50 || force < 100) { //if not presed and not in front



    noTone(12); //dont play music



  }



  else if ((force > 100)) {  //if pressed



    int sound = map(distance, 0, 50, 0, 6);  //map distance to the array of notes

    tone(12, notes[sound]);  //call a certain note depending on distance



  }




}

 

Reflections & Challenges:

One of the challenges we had while working on this project was the weakness of the sensors; if we had an ultrasonic sensor that measured the distance longer and a larger force detecting resistor, we would not have had any trouble playing notes. Therefore, we were forced to limit the user to playing notes (C-D-E-F-G-A) as a result of this.



Week 10 Reading Response / Blinding Lights – Hamdah AlSuwaidi

In synthesizing the insights from TIGOE’s blog posts, “Physical Computing’s Greatest Hits (and misses)” and “Making Interactive Art: Set the Stage, Then Shut Up and Listen,” there emerges a compelling narrative about the nature of human interaction with technology and the role of the creator in guiding this interaction.

The first post examines the myriad ways in which creators harness technology to bridge the gap between art and the human experience. It underscores that the essence of physical computing is not in the machinery itself, but in the potential for human expression and interaction that it affords. TIGOE celebrates the diversity of approaches—from instruments that translate motion into sound to devices that sense and react to our emotions—each offering a unique dialogue between user and machine. This celebration is not just of the end product but of the process and potential for evolution, highlighting that even familiar ideas can be reinvigorated through creative reinterpretation.

The second post, meanwhile, delves into the philosophy behind interactive art. It champions the idea that art is a collaborative exchange and urges creators to step back after setting the scene, allowing the audience to bring their interpretations and experiences into play. This stance challenges the traditional static relationship between art and observer, proposing instead a dynamic interaction where the audience becomes an integral part of the art’s essence.

Both readings converge on the point that in the realm of interactive experiences, whether through physical computing or art, the creator’s role is not to dictate but to facilitate. It’s an invitation to viewers to engage, explore, and co-create, leading to a richer tapestry of experiences. The pieces do not stand as mere displays of technological or artistic prowess but as starting points for a journey that each participant completes in their own unique way.

By bringing together the physical and the interactive, TIGOE illuminates a future of creation that is ever-evolving, deeply personal, and universally accessible. In this future, the boundaries between the creator, the creation, and the consumer are not just blurred but are actively redefined with each interaction, fostering a space where art and technology serve as mediums for communication, learning, and exploration of the human condition. Both readings serve as a manifesto for the modern maker, encouraging a dialogue with technology and audience that is as open-ended as it is profound.

Blinding lights:

After being inspired by The Weeknd’s album ‘After Hours,’ I chose to name my assignment ‘Blinding Lights,’ which reflects the influence of his music had on me.

https://youtube.com/shorts/uRrlVS0TPpw?feature=shared

This Arduino code controls two LEDs (red and blue) based on the light detected by a photoresistor and the position of a potentiometer. The LEDs alternate based on the light level: if it’s dark (light level below 300), they alternate, with the speed of alternation controlled by the potentiometer. If it’s light, both LEDs remain off. The program uses serial output to display the light level detected by the photoresistor.

const int led0 = 3; // Red LED
const int led1 = 5; // Blue LED
const int photoResistor = A1;
const int potentiometer = A0; // Potentiometer connected to analog pin A0

void setup() {
  Serial.begin(9600);
  pinMode(led0, OUTPUT);
  pinMode(led1, OUTPUT);
}

void loop() {
  int lightValue = analogRead(photoResistor);
  Serial.print("Light Value: ");
  Serial.println(lightValue);

  // Read the potentiometer value to control the speed of LED alternation.
  int potValue = analogRead(potentiometer);
  int delayTime = map(potValue, 0, 1023, 50, 1000); // Adjust this range as needed.

  if (lightValue < 300) { // Threshold for photoresistor touch
    // Alternate LEDs when the photoresistor is touched.
    digitalWrite(led0, HIGH);
    digitalWrite(led1, LOW);
    delay(delayTime); // Delay controlled by potentiometer

    digitalWrite(led0, LOW);
    digitalWrite(led1, HIGH);
    delay(delayTime); // Delay controlled by potentiometer
  } else {
    // If the photoresistor is not being touched, turn both LEDs off or keep them in a default state.
    digitalWrite(led0, LOW);
    digitalWrite(led1, LOW);
  }
}

 

Hamdah AlSuwaidi – Unusual switch

For this assignment I have created a switch that activates an LED light when two jumper wires come into contact with a conductive liquid. Initially utilizing saltwater due to its well-known conductive properties, the project later incorporates laban, showcasing the project’s versatility and the unexpected utility of common substances in electronics. The switch operates on the principle that when the liquid completes the circuit between the two wires, the LED is powered on, demonstrating a basic but effective application of electrical conductivity and circuit design.

Concept:

The concept revolves around the exploration of electrical conductivity in liquids and the application of this property in creating an unconventional switch. Conductivity in liquids is often associated with the presence of ions. Saltwater, being rich in ions, is a good conductor of electricity. On the other hand, laban, while less conventional, also contains various salts and minerals that can facilitate the flow of electricity, making it a surprising but effective choice for this experiment.

How It Works:

Circuit Setup: The project utilizes an Arduino board as the control unit, a simple LED light as the output indicator, and two jumper wires inserted into two separate GPIO (General-Purpose Input/Output) pins on the Arduino. One of these pins is set up as an input to detect the circuit’s completion, while the other serves to provide a low voltage signal. The LED is connected to another GPIO pin on the Arduino, configured as an output.

Conductive Medium: The circuit is initially open, meaning the electrical path is incomplete, and the LED remains off. The introduction of a conductive medium (saltwater or laban) bridges the gap between the two jumper wires, allowing current to flow through the liquid and complete the circuit.

Detection and Response: When the Arduino detects the completion of the circuit through its input pin, it triggers the LED to turn on. This response acts as a visual indication that the circuit has been completed through the conductive medium.

Experimentation and Learning: By experimenting with different liquids like saltwater and laban, users can learn about the properties of electrical conductivity in a hands-on manner.

Video:

IMG_5445

Image:


 

Week 8a Reading Response – Hamdah AlSuwaidi

Norman’s article illuminates the complex interplay between attractiveness and usability in design, suggesting that emotional responses to design can greatly influence how users interact with and perceive functionality. This understanding dovetails with Hamilton’s story, as her work in programming not only required an astute technical foundation but also a profound understanding of the user experience—astronauts, in this case—where the emotional stakes were life-and-death rather than mere convenience or pleasure.

Both Norman and Hamilton disrupt conventional narratives in their fields. Norman challenges the notion that design’s utility is purely functional and devoid of emotional consideration. Similarly, Hamilton shatters the glass ceiling, showcasing that women, often relegated to supportive roles during the 1960s, were capable of leading and innovating in technology and engineering, changing the trajectory of history.

The meticulousness in Hamilton’s programming, her foresight in anticipating potential software errors, and her commitment to creating reliable and user-centric software systems reflect the synthesis of form and function that Norman advocates. Hamilton’s designs needed to be not only functional but also to inspire confidence and evoke a sense of security for the astronauts—emotional impacts that were critical to the success of the Apollo missions.

Norman posits that design should elicit positive emotions, which enhance creative thinking and problem-solving capabilities. Hamilton’s work embodies this ethos, where the software she created required imaginative solutions that had to consider the astronauts’ interactions with the technology. Her work went beyond mere function—it was critical in crafting a human-centric experience under extraordinary circumstances.

Margaret Hamilton’s career, while ostensibly in the realm of software engineering, was also deeply entwined with design principles. Her software had to be user-friendly and intuitive for the astronauts, a requirement that predated but is consistent with Norman’s advocacy for designs that account for human emotions. The alignment between Norman’s theoretical framework and Hamilton’s practical application underscores the importance of design thinking in technological innovation.

In essence, Norman’s essay and Hamilton’s narrative converge on a fundamental principle: whether in the form of a teapot or lunar software, good design respects the user’s emotional experience and cognitive processes. Both stories celebrate the potential of human ingenuity when it is applied with empathy and consideration for the user experience.

Through their respective lenses, Norman and Hamilton illuminate the intricacies of human interaction with technology. Norman does so by dissecting the role of emotion in design, while Hamilton does so by pioneering software that supported one of humanity’s most emotionally resonant achievements. Both exemplify how the integration of form, function, and feeling can result in extraordinary usability and transformative experiences.

The reading of these two narratives, interwoven, culminates in an appreciation for the nuanced role that emotion and human-centric design play in the advancement and acceptance of technology. They advocate for a vision where technology and design do not merely serve human needs but also enrich the human spirit, a vision as expansive and hopeful as space itself.

Midterm – Hamdah AlSuwaidi

Recently, I had the opportunity to visit The Metropolitan Museum of Art (The MET) and was truly inspired by the diverse and rich history encapsulated within its walls. This visit sparked an idea in me to design an exhibit for The MET’s Costume Institute, focusing on the evolution of haute couture through iconic designs from renowned fashion houses. My midterm, aims to showcase the enduring allure and innovation of haute couture, highlighting how designers have redefined beauty and style over the decades.


By focusing on the individual stories that each garment tells about its era, the exhibit aims to provide a rich, textual narrative that captures the essence and evolution of haute couture across different periods.

Interactive elements, such as clickable images that reveal the history and significance of each piece, are integral to the exhibit. These features are designed to engage users, encouraging them to delve deeper into each garment’s story and understand its place within the broader narrative of fashion history.

let titleSize = 40;
let subtitleSize2 = 20;
let subtitleSize = 10;
let  bg, bg2;
let dress1, dress1Zoom1, dress1Zoom2, dress1Zoom3, dress1Zoom4, dress1Zoom5;
let dress2, dress2Zoom1, dress2Zoom2, dress2Zoom3, dress2Zoom4;
let dress3, dress3Zoom1, dress3Zoom2, dress3Zoom3;
let dress4, dress4Zoom1, dress4Zoom2, dress4Zoom3, dress4Zoom4;
let dress5, dress5Zoom1, dress5Zoom2, dress5Zoom3, dress5Zoom4, dress5Zoom5;
let dress6, dress6Zoom1, dress6Zoom2, dress6Zoom3, dress6Zoom4;
let scene = "main"; // Start with the exhibit scene
let bgsound;



function preload() {
  bgsound = loadSound('bgsoundfile.mp3')
  bg = loadImage('bg.jpeg');
  bg2 = loadImage('fullscreen.png'); // The fullscreen image for the exhibit
  //dress1
  dress1 = loadImage('dress1.png');
  dress1Zoom1 = loadImage('dress1Zoom1.png');
  dress1Zoom2 = loadImage('dress1Zoom2.png');
  dress1Zoom3 = loadImage('dress1Zoom3.png');
  dress1Zoom4 = loadImage('dress1Zoom4.png');
  dress1Zoom5 = loadImage('dress1Zoom5.png');
  //dress2
  dress2 = loadImage('dress2.png');
  dress2Zoom1 = loadImage('dress2Zoom1.png');
  dress2Zoom2 = loadImage('dress2Zoom2.png');
  dress2Zoom3 = loadImage('dress2Zoom3.png');
  dress2Zoom4 = loadImage('dress2Zoom4.png');
  //dress3
  dress3 = loadImage('dress3.png');
  dress3Zoom1 = loadImage('dress3Zoom1.png');
  dress3Zoom2 = loadImage('dress3Zoom2.png');
  dress3Zoom3 = loadImage('dress3Zoom3.png');
  //dress4
  dress4 = loadImage('dress4.png');
  dress4Zoom1 = loadImage('dress4Zoom1.png');
  dress4Zoom2 = loadImage('dress4Zoom2.png');
  dress4Zoom3 = loadImage('dress4Zoom3.png');
  dress4Zoom4 = loadImage('dress4Zoom4.png');
  //dress5
  dress5 = loadImage('dress5.png');
  dress5Zoom1 = loadImage('dress5Zoom1.png');
  dress5Zoom2 = loadImage('dress5Zoom2.png');
  dress5Zoom3 = loadImage('dress5Zoom3.png');
  dress5Zoom4 = loadImage('dress5Zoom4.png');
  dress5Zoom5 = loadImage('dress5Zoom5.png');
  //dress6
  dress6 = loadImage('dress6.png');
  dress6Zoom1 = loadImage('dress6Zoom1.png');
  dress6Zoom2 = loadImage('dress6Zoom2.png');
  dress6Zoom3 = loadImage('dress6Zoom3.png');
  dress6Zoom4 = loadImage('dress6Zoom4.png');
  
}
function setup() {
  createCanvas(720, 400);
  textSize(titleSize);
  textAlign(CENTER, CENTER);
   bgsound.loop();
  
}
function draw() {
  
  if (scene === "main") {
    drawMainScene();
  } else if (scene === "exhibit") {
    drawExhibitScene();
  } else if (scene.startsWith("zoomedInDress")) {
    drawZoomedScene();
  } bgsound.play();
  
}
function drawMainScene() {
  background(bg);
  noStroke();
  fill(0);
  textSize(titleSize);
  text("THE MET", width / 3 + 120, height / 3 - 80);
  textSize(subtitleSize2);
  text("THE COSTUME INSTITUTE", width / 2, height / 2 - 110);
  fill(0);
  textSize(subtitleSize);
  text("Touch the start button to begin!", width / 2, height / 2 - 80);
  // Start Button
  fill(255);
  rect(width / 2 - 50, height / 2 + 50, 100, 40, 10);
  fill(0);
  textSize(16);
  text("Start", width / 2, height / 2 + 70);
}
function drawExhibitScene() {
  background(bg2); // Use the fullscreen image as the background for the exhibit
  // Back Button, only show if we're not in the initial exhibit scene
  fill(255); // White color
  rect(20, 20, 60, 30, 10);
  fill(0); // Black color
  textSize(16);
  text("Back", 50, 35);
}
function drawZoomedScene() {
  let zoomedImage;
  switch (scene) {
    case "zoomedInDress1_1":
      zoomedImage = dress1Zoom1;
      break;
    case "zoomedInDress1_2":
      zoomedImage = dress1Zoom2;
      break;
    case "zoomedInDress1_3":
      zoomedImage = dress1Zoom3;
      break;
    case "zoomedInDress1_4":
      zoomedImage = dress1Zoom4;
      break;
    case "zoomedInDress1_5":
      zoomedImage = dress1Zoom5;
      break;
    case "zoomedInDress2_1":
      zoomedImage = dress2Zoom1;
      break;
    case "zoomedInDress2_2":
      zoomedImage = dress2Zoom2;
      break;
    case "zoomedInDress2_3":
      zoomedImage = dress2Zoom3;
      break;
    case "zoomedInDress2_4":
      zoomedImage = dress2Zoom4;
      break;
    case "zoomedInDress3_1":
      zoomedImage = dress3Zoom1;
      break;
    case "zoomedInDress3_2":
      zoomedImage = dress3Zoom2;
      break;
    case "zoomedInDress3_3":
      zoomedImage = dress3Zoom3;
      break;
    case "zoomedInDress4_1":
      zoomedImage = dress4Zoom1;
      break;
    case "zoomedInDress4_2":
      zoomedImage = dress4Zoom2;
      break;
    case "zoomedInDress4_3":
      zoomedImage = dress4Zoom3;
      break;
    case "zoomedInDress4_4":
      zoomedImage = dress4Zoom4;
      break;
    case "zoomedInDress5_1":
      zoomedImage = dress5Zoom1;
      break;
    case "zoomedInDress5_2":
      zoomedImage = dress5Zoom2;
      break;
    case "zoomedInDress5_3":
      zoomedImage = dress5Zoom3;
      break;
    case "zoomedInDress5_4":
      zoomedImage = dress5Zoom4;
      break;
    case "zoomedInDress5_5":
      zoomedImage = dress5Zoom5;
      break; 
    case "zoomedInDress6_1":
      zoomedImage = dress6Zoom1;
      break;
    case "zoomedInDress6_2":
      zoomedImage = dress6Zoom2;
      break;
    case "zoomedInDress6_3":
      zoomedImage = dress6Zoom3;
      break;
    case "zoomedInDress6_4":
      zoomedImage = dress6Zoom4;
      break;  
  }
  background(zoomedImage); // Display the zoomed-in image on full canvas
  // Back Button
  fill(255); // White color
  rect(20, 20, 60, 30, 10);
  fill(0); // Black color
  textSize(16);
  text("Back", 50, 35);
}
function mouseClicked() {
   if (!bgsound.isPlaying()) { // Check if the sound is not already playing
    bgsound.loop(); // Start playing the sound
  }
 
  if (scene === "main") {
    // If the Start button is clicked, change to the exhibit scene
    if (mouseX > width / 2 - 50 && mouseX < width / 2 + 50 && mouseY > height / 2 + 50 && mouseY < height / 2 + 90) {
      scene = "exhibit";
      
    }
  } else if (scene === "exhibit") {
    // Check if the click is within the back button's coordinates
    if (mouseX > 20 && mouseX < 80 && mouseY > 20 && mouseY < 50) {
      scene = "main";
     
    }
    // Check if the click is within Dress1's designated area
    else if (mouseX > 148 && mouseX < 228 && mouseY > 43 && mouseY < 149) {
      scene = "zoomedInDress1_1";
     
    }
    // Check if the click is within Dress2's designated area
    else if (mouseX > 325 && mouseX < 405 && mouseY > 44 && mouseY < 149) {
      scene = "zoomedInDress2_1";
      
    }
    //  Check if the click is within Dress3's designated area
    else if (mouseX > 450 && mouseX < 580 && mouseY > 44 && mouseY < 149) {
      scene = "zoomedInDress3_1";
      
    }
    //  Check if the click is within Dress4's designated area
    else if (mouseX > 148 && mouseX < 229 && mouseY > 203 && mouseY < 308) {
      scene = "zoomedInDress4_1";
      
    }
    //  Check if the click is within Dress5's designated area
    else if (mouseX > 323 && mouseX < 406 && mouseY > 201 && mouseY < 309) {
      scene = "zoomedInDress5_1";
      
    }
    //  Check if the click is within Dress6's designated area
    else if (mouseX > 450 && mouseX < 580 && mouseY > 201 && mouseY < 307) {
      scene = "zoomedInDress6_1";
      
 
    }
    
  } else if (scene.startsWith("zoomedInDress")) {
    // If the Back button is clicked in a zoomed-in scene, go back to the exhibit
    if (mouseX > 20 && mouseX < 80 && mouseY > 20 && mouseY < 50) {
      scene = "exhibit";
  
    } else {
      // Cycle through the zoomed-in images
      let parts = scene.split('_');
      let dressNum = parts[0].replace("zoomedInDress", "");
      let zoomLevel = parseInt(parts[1]);
      zoomLevel = zoomLevel >= 4 ? 1 : zoomLevel + 1; // Loop back after the last image for dress1 and dress2
      if(dressNum === "3" && zoomLevel > 3) zoomLevel = 1; // Since dress3 has only 3 zoom levels
      scene = `zoomedInDress${dressNum}_${zoomLevel}`;
    }
  }
}

 

 

Midterm Progress / Reading Response – Hamdah AlSuwaidi

 Midterm Progress:

For my midterm project, I’m taking on the challenge of designing a captivating costume exhibit for The MET’s Costume Institute. The exhibit will showcase the evolution of haute couture through iconic designs from renowned fashion houses, spanning different eras and design philosophies.

The overarching theme of the exhibit is “Timeless Elegance: A Journey Through Fashion History.” My aim is to highlight the enduring allure and innovation of haute couture, exploring how designers have redefined beauty and style over the decades.

1. Homepage:
– The homepage welcomes visitors to the online exhibit with a visually appealing layout featuring the exhibit’s title, a brief description, and navigation options.

2. Navigation Menu:
– A navigation menu at the top or side of the webpage allows visitors to easily access different sections of the exhibit, including:
– Explore: Provides access to the main exhibit layout where visitors can view featured designers and garments.
– Audio Guides: Offers a collection of audio commentary on select pieces.
– Search: Enables visitors to search for specific designers, garments, or fashion movements.
– About: Provides information about the exhibit, its curators, and contributors.

3. Explore Section:
– Clicking on the “Explore” option takes visitors to the main exhibit layout, which may resemble a gallery or virtual space.
– Visitors can navigate through different areas of the exhibit by clicking or tapping on designated hotspots or arrows.
– Clicking on a designer’s name or garment reveals detailed information, including descriptions, historical context, and images.

4. Audio Guides:
– The “Audio Guides” section presents visitors with a curated collection of audio commentary on select pieces within the exhibit.
– Visitors can listen to the audio commentary by clicking on specific garments or audio icons associated with them.

5. Search Functionality:
– The “Search” option allows visitors to search for specific designers, garments, or fashion movements.
– Visitors can enter keywords or phrases into the search bar to find relevant content within the exhibit.
– Search results display relevant garments, designers, or topics, with clickable links to access more information.

Interactive Elements:
– Throughout the exhibit, interactive elements such as clickable images, videos, and multimedia presentations provide additional context and engagement.
– Visitors can interact with these elements by clicking or tapping on them to access related content or animations.

Some examples:

7. Responsive Design:
– The online exhibit is designed to be responsive, ensuring a seamless experience across different devices and screen sizes.
– Whether visitors access the exhibit on a desktop computer, tablet, or smartphone, the layout and functionality adapt to provide an optimal viewing experience.

  1. Maintaining Engagement: Keeping visitors engaged throughout their online exhibit experience is crucial. Unlike in-person exhibits where visitors may spend hours exploring, online visitors may have shorter attention spans. Designing captivating visuals, interactive elements, and compelling content is essential to maintain visitor interest and encourage exploration.
  2. Audio and Video Integration: Integrating audio and video content into the exhibit may present challenges such as ensuring cross-browser compatibility, synchronizing multimedia elements with other interactive elements or animations, and optimizing playback performance for smooth audio/video streaming.
let titleSize = 40; // Decreased the title size
let subtitleSize = 20; // Decreased the subtitle size

function preload(){
   hangerImage = loadImage('Hanger.png'); // Load hanger image }
}
function setup() {
  createCanvas(windowWidth, windowHeight);
  textSize(titleSize);
  textAlign(CENTER, CENTER);
}

function draw() { background(255); // Set background color to white
if (mouseIsPressed || mouseX != pmouseX || mouseY != pmouseY) {
  // Display hanger image on mouse hover
  image(hangerImage, mouseX, mouseY, 70, 50);
}
                
 // Title
                 
fill(166, 0, 0); // Set text color to red
  textSize(titleSize);
  text("Welcome to Timeless Elegance", width / 2, height / 2 - 50);
  
  // Subtitle
  fill(0); // Set text color to red
  textSize(subtitleSize);
  text("Touch the screen to begin your journey", width / 2, height / 2 + 20);
}

function mouseClicked() {
  // Trigger next screen or action when the screen is touched/clicked
  // For example, navigate to the main exhibit layout
}

The hanger icon serves as a visual representation of fashion and garment design, reinforcing the theme of the exhibit. It symbolizes the process of selecting, showcasing, and appreciating designer garments, further immersing visitors in the world of fashion.Changing the mouse cursor to a hanger creates a more immersive experience for visitors, immediately signaling that they are entering a fashion-themed environment. This subtle visual cue helps transport visitors into the world of haute couture and sets the tone for the exhibit.

https://docs.google.com/document/d/1wQb92P4HcfuLNuzHEYyvs3ZUFQNo6hspwGtPbJLv53Q/edit?usp=sharing (More details about the costume institute and what dress will be included in the exhibit)

Reading response:

The reading on “Computer Vision for Artists and Designers” delves into the increasing accessibility of computer vision technology to artists and designers, facilitated by user-friendly software and open-source communities. It showcases various projects, including Rafael Lozano-Hemmer’s intriguing installation “Standards and Double Standards” (2004), where belts controlled by a computer vision-based tracking system rotate to follow individuals, offering an unintentional yet captivating form of interaction.

However, the ethical implications become pronounced with projects like Suicide Box by the Bureau of Inverse Technology (1996), which utilized motion-detection to record real data of suicides, raising concerns about privacy and surveillance. While such data might aid in locating missing individuals, it blurs ethical boundaries, sparking controversy.

Moreover, the reading outlines different problems addressed by vision algorithms, such as motion detection and object tracking, underscoring their relevance in design considerations. The introduction of “Telecentric lenses” offers insights into improving object recognition, albeit with drawbacks like cost and distortion issues, prompting reflection on their judicious usage.

The discussion expands to the societal acceptance of constant surveillance through technologies like facial recognition, prompting introspection on privacy norms. This leads to questioning the boundaries between innovation and intrusion, highlighting the need for ethical frameworks in technology adoption.

In reflecting on the reading, two artworks stand out for their distinct approaches to computer vision. Rafael Lorenzo-Hemmer’s “Standards and Double Standards” impresses with its inventive use of space and objects, blurring the lines between digital and tangible realms. In contrast, Christopher Moller’s “Cheese” raises questions about the advancements in facial recognition technology and its potential implications for art and society.

Assignment 4 / Reading response – Hamdah AlSuwaidi

For this assignment, the goal was to combine various elements such as text, background scenery, and interactive components to create a visually appealing and engaging composition.

In this particular assignment, the background consists of a gradient sky with clouds, which provides a serene and calming atmosphere. The addition of colorful butterflies adds a touch of whimsy and liveliness to the scene. The choice of background and butterflies was made to create a harmonious and cohesive composition that aligns with the theme of nature and tranquility. Additionally, using a similar background pattern as the previous assignment helps create a consistent visual theme across multiple assignments, reinforcing the idea of a recurring pattern or motif.

 

1. Setup Function:
– Initializes the canvas and creates arrays to hold instances of butterflies, clouds, and flowers.
– Generates multiple instances of butterflies, clouds, and flowers with random positions on the canvas.

2. Draw Function:
– Renders the background with a gradient sky and clouds.
– Updates and displays each cloud’s position on the canvas.
– Updates and displays each butterfly’s position and appearance.
– Displays each flower on the canvas.

3. Butterfly Class:
– Represents a butterfly object with properties such as position, velocity, color, and size.
– The `update()` method updates the butterfly’s position and may change its direction randomly.
– The `display()` method renders the butterfly’s wings with a specified color pattern.

4. Cloud Class:
– Represents a cloud object with properties such as position, velocity, and size.
– The `update()` method updates the cloud’s position, ensuring it moves across the screen.
– The `display()` method renders the cloud as a set of ellipses representing its shape.

5. Flower Class:
– Represents a flower object with properties such as position, size, and color.
– The `display()` method renders the flower as an ellipse representing its center and a smaller red ellipse above, representing its stigma.

6. Interactivity:
– The `mouseClicked()` function triggers a change in butterfly colors when the mouse is clicked. This adds an interactive element to the artwork, allowing users to alter the visual composition dynamically.

let butterflies = [];
let clouds = [];
let butterflyColors = [
  [255, 20, 147], // Pink
  [128, 0, 128], // Purple
  [255, 255, 0] // Yellow
];
let currentColorIndex = 0;

function setup() {
  createCanvas(700, 500);
  
  // Create a flock of butterflies
  for (let i = 0; i < 10; i++) {
    let butterfly = new Butterfly(random(width), random(height), currentColorIndex);
    butterflies.push(butterfly);
  }
  
  // Create some clouds
  for (let i = 0; i < 5; i++) {
    let cloud = new Cloud(random(width), random(height));
    clouds.push(cloud);
  }
  
  
}

function draw() {
  // Draw gradient sky background
  background(135, 206, 250); // Light blue
  for (let y = 0; y < height; y++) {
    let inter = map(y, 0, height, 0, 1);
    let c = lerpColor(color(135, 206, 250), color(255, 255, 255), inter);
    stroke(c);
    line(0, y, width, y);
  }
  
  // Display and update clouds
  for (let cloud of clouds) {
    cloud.display();
    cloud.update();
  }
  
  // Update and display each butterfly
  for (let i = 0; i < butterflies.length; i++) {
    butterflies[i].update();
    butterflies[i].display();
  }
  

  
  // Display "Hamdah" text
  textSize(80);
  textAlign(CENTER, CENTER);
  fill(0); // Black color
  text("Hamdah", width / 2, height / 2);
}

function mouseClicked() {
  // Change butterfly colors on mouse click
  currentColorIndex = (currentColorIndex + 1) % butterflyColors.length;
  for (let i = 0; i < butterflies.length; i++) {
    butterflies[i].changeColor(currentColorIndex);
  }
}

class Butterfly {
  constructor(x, y, colorIndex) {
    this.position = createVector(x, y);
    this.velocity = createVector(random(-1, 1), random(-1, 1));
    this.colorIndex = colorIndex;
    this.size = random(20, 40);
    this.angle = random(TWO_PI);
  }
  
  update() {
    // Update position
    this.position.add(this.velocity);
    
    // Change direction randomly
    if (random() < 0.01) {
      this.velocity.rotate(random(-PI / 4, PI / 4));
    }
    
    // Wrap around screen
    this.position.x = (this.position.x + width) % width;
    this.position.y = (this.position.y + height) % height;
  }
  
  display() {
    // Draw butterfly wings with pattern
    fill(0); // Black
    noStroke();
    ellipse(this.position.x, this.position.y, this.size, this.size / 2);
    let wingOffset = this.size / 4;
    let wingSize = this.size / 2;
    push();
    translate(this.position.x, this.position.y);
    rotate(this.angle);
    fill(butterflyColors[this.colorIndex][0], butterflyColors[this.colorIndex][1], butterflyColors[this.colorIndex][2]); // Butterfly color
    ellipse(-wingOffset, 0, wingSize, wingSize * 2);
    ellipse(wingOffset, 0, wingSize, wingSize * 2);
    fill(0); // Black
    ellipse(-wingOffset, 0, wingSize / 2, wingSize);
    ellipse(wingOffset, 0, wingSize / 2, wingSize);
    pop();
  }
  
  changeColor(colorIndex) {
    this.colorIndex = colorIndex;
  }
}

class Cloud {
  constructor(x, y) {
    this.position = createVector(x, y);
    this.velocity = createVector(random(-0.5, 0.5), 0);
    this.size = random(50, 100);
  }
  
  update() {
    this.position.add(this.velocity);
    if (this.position.x > width + this.size) {
      this.position.x = -this.size;
    }
    if (this.position.x < -this.size) {
      this.position.x = width + this.size;
    }
  }
  
  display() {
    noStroke();
    fill(255);
    ellipse(this.position.x, this.position.y, this.size * 1.5, this.size);
    ellipse(this.position.x - this.size / 3, this.position.y - this.size / 4, this.size, this.size * 0.8);
    ellipse(this.position.x + this.size / 3, this.position.y - this.size / 4, this.size, this.size * 0.8);
  }
}

  

Reading Response:

In his seminal work, “The Design of Everyday Things,” Don Norman meticulously dissects the intricate relationship between design and user experience, shedding light on the fundamental principles that govern successful product interaction. Norman’s exploration of affordances resonates deeply with my own understanding of design, emphasizing the pivotal role of intuitive functionality in fostering seamless user-product relationships.

Consider, for instance, the ubiquitous smartphone interface. A well-designed interface intuitively guides users through its myriad functions, leveraging affordances and signifiers to streamline interactions. Icons and gestures serve as visual cues, effortlessly communicating their intended actions. When users tap an icon, they anticipate launching an app; when they swipe, they expect to navigate between screens. These intuitive interactions not only reduce the cognitive burden on users but also enhance their overall satisfaction with the device.

However, the efficacy of design extends beyond mere functionality; it encompasses a nuanced understanding of users’ evolving needs and technological literacy. As technology continues to evolve, so too does the language of interactive design. Novel features such as facial recognition and fingerprint identification, once considered exotic, have now become commonplace, ingrained within the lexicon of modern devices. Yet, the assimilation of these innovations into the user experience requires careful consideration of contextual factors and prior familiarity.

For instance, imagine a scenario where a user encounters a new smart home device equipped with voice recognition capabilities. To a tech-savvy individual accustomed to interacting with virtual assistants, such as Siri or Alexa, the process may feel intuitive, akin to conversing with a familiar friend. However, for someone less acquainted with these technologies, the experience may prove bewildering, necessitating a more gradual onboarding process to bridge the gap between novelty and comprehension.

This underscores the dynamic nature of interactive design, which continually adapts to accommodate emerging technologies and diverse user demographics. As designers, we must strive not only to anticipate users’ needs but also to cultivate inclusive and accessible interfaces that resonate across varying levels of technological proficiency. By embracing this iterative approach and prioritizing intuitive design, we can forge meaningful connections between users and products, enriching lives and experiences in the process.